Updating ChangeLog for 4.22.10
[centerim.git] / src / hooks / jabberhook.cc
blob91e81c2f8780e4a8ba3b2a67bab17deda3d8f748
1 /*
3 * centerim Jabber protocol handling class
4 * $Id: jabberhook.cc,v 1.85 2005/08/26 11:01:49 konst Exp $
6 * Copyright (C) 2002-2005 by Konstantin Klyagin <k@thekonst.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
25 #include "icqcommon.h"
27 #ifdef BUILD_JABBER
29 #include "jabberhook.h"
30 #include "icqface.h"
31 #include "imlogger.h"
32 #include "eventmanager.h"
33 #include "icqgroups.h"
34 #include "impgp.h"
35 #include "icqcontacts.h"
36 #include "centerim.h"
38 #ifdef HAVE_SSTREAM
39 #include <sstream>
40 #else
41 #include <strstream>
42 #endif
44 #ifdef HAVE_LIBOTR
45 #include "imotr.h"
46 #endif
49 #define DEFAULT_CONFSERV "conference.jabber.org"
50 #define PERIOD_KEEPALIVE 30
52 #define NOTIFBUF 512
54 //base64 enc/dec functions to work with binary data in xmpp
55 static char b64table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
57 static char *base64_encode( char *buffer, int bufferLen )
59 if ( buffer==NULL || bufferLen<=0 )
60 return NULL;
62 char* res = (char*)malloc(((( bufferLen+2 )*4 )/3 ) + 1);
63 if ( res == NULL )
64 return NULL;
66 unsigned char igroup[3];
67 int nGroups = 0;
68 char *r = res;
69 char *peob = buffer + bufferLen;
70 char *p;
71 for ( p = buffer; p < peob; ) {
72 igroup[ 0 ] = igroup[ 1 ] = igroup[ 2 ] = 0;
73 int n;
74 for ( n=0; n<3; n++ ) {
75 if ( p >= peob ) break;
76 igroup[n] = ( unsigned char ) *p;
77 p++;
80 if ( n > 0 ) {
81 r[0] = b64table[ igroup[0]>>2 ];
82 r[1] = b64table[ (( igroup[0]&3 )<<4 ) | ( igroup[1]>>4 ) ];
83 r[2] = b64table[ (( igroup[1]&0xf )<<2 ) | ( igroup[2]>>6 ) ];
84 r[3] = b64table[ igroup[2]&0x3f ];
86 if ( n < 3 ) {
87 r[3] = '=';
88 if ( n < 2 )
89 r[2] = '=';
91 r += 4;
92 } }
94 *r = '\0';
96 return res;
99 static char *base64_decode(const char *str, int *ret_len)
101 if( !str )
102 return NULL;
103 char *out = NULL;
104 char tmp = 0;
105 const char *c;
106 int tmp2 = 0;
107 int len = 0, n = 0;
110 c = str;
112 while (*c) {
113 if (*c >= 'A' && *c <= 'Z') {
114 tmp = *c - 'A';
115 } else if (*c >= 'a' && *c <= 'z') {
116 tmp = 26 + (*c - 'a');
117 } else if (*c >= '0' && *c <= 57) {
118 tmp = 52 + (*c - '0');
119 } else if (*c == '+') {
120 tmp = 62;
121 } else if (*c == '/') {
122 tmp = 63;
123 } else if (*c == '\r' || *c == '\n') {
124 c++;
125 continue;
126 } else if (*c == '=') {
127 if (n == 3) {
128 out = (char*)realloc(out, len + 2);
129 out[len] = (char)(tmp2 >> 10) & 0xff;
130 len++;
131 out[len] = (char)(tmp2 >> 2) & 0xff;
132 len++;
133 } else if (n == 2) {
134 out = (char*)realloc(out, len + 1);
135 out[len] = (char)(tmp2 >> 4) & 0xff;
136 len++;
138 break;
140 tmp2 = ((tmp2 << 6) | (tmp & 0xff));
141 n++;
142 if (n == 4) {
143 out = (char*)realloc(out, len + 3);
144 out[len] = (char)((tmp2 >> 16) & 0xff);
145 len++;
146 out[len] = (char)((tmp2 >> 8) & 0xff);
147 len++;
148 out[len] = (char)(tmp2 & 0xff);
149 len++;
150 tmp2 = 0;
151 n = 0;
153 c++;
156 out = (char*)realloc(out, len + 1);
157 out[len] = 0;
159 if (ret_len != NULL)
160 *ret_len = len;
162 return out;
165 static void jidsplit(const string &jid, string &user, string &host, string &rest) {
166 int pos;
167 user = jid;
169 if((pos = user.find("/")) != -1) {
170 rest = user.substr(pos+1);
171 user.erase(pos);
174 if((pos = user.find("@")) != -1) {
175 host = user.substr(pos+1);
176 user.erase(pos);
178 else {
179 host = user;
180 user = (string)"";
184 static string jidtodisp(const string &jid) {
185 string user, host, rest;
186 jidsplit(jid, user, host, rest);
188 if(!user.empty())
189 user += (string) "@" + host;
190 else
191 user = host;
193 return user;
196 static imstatus get_presence(std::map<string, pair<char, imstatus> > res) // <resource, <prio, status> >
198 if (res.empty())
199 return offline;
200 imstatus result = offline;
201 char prio = -127;
202 for (map<string, pair<char, imstatus> >::iterator it = res.begin(); it!= res.end(); it++)
204 if (it->second.first>prio)
206 result = it->second.second;
207 prio = it->second.first;
210 return result;
214 // ----------------------------------------------------------------------------
216 jabberhook jhook;
218 string jabberhook::jidnormalize(const string &jid) const {
219 if(find(agents.begin(), agents.end(), jid) != agents.end())
220 return jid;
222 string user, host, rest;
223 jidsplit(jid, user, host, rest);
225 if(host.empty())
226 host = conf->getourid(proto).server;
228 if (user.empty())
229 user = host;
230 else
231 user += (string) "@" + host;
232 if(!rest.empty()) user += (string) "/" + rest;
233 return user;
236 jabberhook::jabberhook(): abstracthook(jabber), jc(0), flogged(false), fonline(false) {
237 fcapabs.insert(hookcapab::setaway);
238 fcapabs.insert(hookcapab::setextstatus);
239 fcapabs.insert(hookcapab::fetchaway);
240 fcapabs.insert(hookcapab::authrequests);
241 fcapabs.insert(hookcapab::directadd);
242 fcapabs.insert(hookcapab::flexiblesearch);
243 fcapabs.insert(hookcapab::flexiblereg);
244 fcapabs.insert(hookcapab::visibility);
245 fcapabs.insert(hookcapab::ssl);
246 fcapabs.insert(hookcapab::changedetails);
247 fcapabs.insert(hookcapab::conferencing);
248 fcapabs.insert(hookcapab::groupchatservices);
249 fcapabs.insert(hookcapab::changenick);
250 fcapabs.insert(hookcapab::changeabout);
251 fcapabs.insert(hookcapab::version);
252 #ifdef HAVE_THREAD
253 fcapabs.insert(hookcapab::files);
254 #endif
255 fcapabs.insert(hookcapab::pgp);
256 fcapabs.insert(hookcapab::acknowledgements);
259 jabberhook::~jabberhook() {
262 void jabberhook::init() {
263 char rnd[9];
264 snprintf(rnd, 9, "%X%X", rand()%0xFFFF, rand()%0xFFFF);
265 uuid = rnd;
266 manualstatus = conf->getstatus(proto);
269 void jabberhook::connect() {
270 icqconf::imaccount acc = conf->getourid(proto);
271 string jid = getourjid();
274 log(logConnecting);
276 /* TODO: is there really a need for COPYING these char-arrays
277 * shoudn't it be possible to feed the c_str() directly into jab_new
278 * and get rid of the copying ?
280 char *cjid = strdup(jid.c_str());
281 char *cpass = strdup(acc.password.c_str());
282 char *cserver = strdup(acc.server.c_str());
284 regmode = flogged = fonline = false;
286 if(jc){
287 jab_delete(jc);
290 jc = jab_new(cjid, cpass, cserver, acc.port,
291 acc.additional["ssl"] == "1" ? 1 : 0);
293 jab_packet_handler(jc, &packethandler);
294 jab_state_handler(jc, &statehandler);
296 if(conf->getdebug())
297 jab_logger(jc, &jlogger);
299 if(jc->user) {
300 fonline = true;
301 jstate = STATE_CONNECTING;
302 statehandler(0, -1);
303 jab_start(jc);
306 free (cjid);
307 free (cpass);
308 free (cserver);
311 void jabberhook::disconnect() {
312 // announce it to everyone else
313 setjabberstatus(offline, "");
315 // announce it to the user
316 statehandler(jc, JCONN_STATE_OFF);
318 // close the connection
319 jab_stop(jc);
320 jab_delete(jc);
321 jc = 0;
324 void jabberhook::exectimers() {
325 if(logged()) {
326 if(timer_current-timer_keepalive > PERIOD_KEEPALIVE) {
327 jab_send_raw(jc, " \t ");
328 timer_keepalive = timer_current;
333 void jabberhook::main() {
334 xmlnode x, z;
335 char *cid;
337 if(jc && jc->state == JCONN_STATE_CONNECTING) {
338 jab_start(jc);
339 return;
342 jab_poll(jc, 0);
344 if(jstate == STATE_CONNECTING) {
345 if(jc) {
346 x = jutil_iqnew(JPACKET__GET, NS_AUTH);
347 cid = jab_getid(jc);
348 xmlnode_put_attrib(x, "id", cid);
349 id = atoi(cid);
351 z = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "username");
352 xmlnode_insert_cdata(z, jc->user->user, (unsigned) -1);
353 jab_send(jc, x);
354 xmlnode_free(x);
356 jstate = STATE_GETAUTH;
359 if(!jc || jc->state == JCONN_STATE_OFF) {
360 face.log(_("+ [jab] unable to connect to the server"));
361 fonline = false;
365 if(!jc) {
366 statehandler(jc, JCONN_STATE_OFF);
368 } else if(jc->state == JCONN_STATE_OFF || jc->fd == -1) {
369 statehandler(jc, JCONN_STATE_OFF);
374 void jabberhook::getsockets(fd_set &rfds, fd_set &wfds, fd_set &efds, int &hsocket) const {
375 if(jc) {
376 if (jc->cw_state & CW_CONNECT_WANT_READ)
377 FD_SET(jc->fd, &rfds);
378 else if (jc->cw_state & CW_CONNECT_WANT_WRITE)
379 FD_SET(jc->fd, &wfds);
380 else
381 FD_SET(jc->fd, &rfds);
382 hsocket = max(jc->fd, hsocket);
386 bool jabberhook::isoursocket(fd_set &rfds, fd_set &wfds, fd_set &efds) const {
387 if(jc) return FD_ISSET(jc->fd, &rfds) || FD_ISSET(jc->fd, &wfds);
388 return false;
391 bool jabberhook::online() const {
392 return fonline;
395 bool jabberhook::logged() const {
396 return fonline && flogged;
399 bool jabberhook::isconnecting() const {
400 return fonline && !flogged;
403 bool jabberhook::enabled() const {
404 return true;
407 bool jabberhook::send(const imevent &ev) {
408 icqcontact *c = clist.get(ev.getcontact());
409 string text, cname, enc;
411 if(c) {
412 if(ev.gettype() == imevent::message) {
413 const immessage *m = static_cast<const immessage *>(&ev);
414 text = m->gettext();
416 } else if(ev.gettype() == imevent::url) {
417 const imurl *m = static_cast<const imurl *>(&ev);
418 text = m->geturl() + "\n\n" + m->getdescription();
420 } else if(ev.gettype() == imevent::file) {
421 const imfile *m = static_cast<const imfile *>(&ev);
422 vector<imfile::record> files = m->getfiles();
423 vector<imfile::record>::const_iterator ir = files.begin();
425 string cjid_str = jidtodisp(ev.getcontact().nickname);
426 transform(cjid_str.begin(), cjid_str.end(), cjid_str.begin(), ::tolower);
427 char *cjid = strdup(cjid_str.c_str());
429 struct send_file *trans_file = (struct send_file *)malloc( sizeof( struct send_file ) );
430 srfiles[cjid].first = (*m);
431 back_srfiles[*m] = cjid; //backward comp. , little hack :(
433 trans_file->full_jid_name = strdup(jhook.full_jids[cjid].c_str());
434 trans_file->id = NULL;
435 trans_file->transfer_type = 5;
436 trans_file->host = NULL;
437 trans_file->url = NULL;
438 trans_file->sid_from_to = NULL;
440 srfiles[cjid].second.first = trans_file;
441 srfiles[cjid].second.second = 0;
444 face.transferupdate(files[0].fname, *m, icqface::tsInit, files[0].size, 0);
446 send_file(cjid);
448 } else if(ev.gettype() == imevent::authorization) {
449 const imauthorization *m = static_cast<const imauthorization *> (&ev);
450 char *cjid = strdup(jidnormalize(ev.getcontact().nickname).c_str());
451 xmlnode x = 0;
453 switch(m->getauthtype()) {
454 case imauthorization::Granted:
455 x = jutil_presnew(JPACKET__SUBSCRIBED, cjid, 0);
456 break;
457 case imauthorization::Rejected:
458 x = jutil_presnew(JPACKET__UNSUBSCRIBED, cjid, 0);
459 break;
460 case imauthorization::Request:
461 x = jutil_presnew(JPACKET__SUBSCRIBE, cjid, 0);
462 break;
465 if(x) {
466 jab_send(jc, x);
467 xmlnode_free(x);
470 free(cjid);
472 return true;
475 text = rusconv("ku", text);
477 #ifdef HAVE_GPGME
478 if(pgp.enabled(ev.getcontact())) {
479 enc = pgp.encrypt(text, c->getpgpkey(), proto);
480 if (enc.empty() && !text.empty()) // probably encryption error
481 return false;
482 text = "This message is encrypted.";
484 #endif
486 #ifdef HAVE_LIBOTR
487 if (!otr.send_message(proto, jidnormalize(ev.getcontact().nickname), text))
489 return true;
491 #endif
493 /* TODO: do these really needs to be copied? */
494 char *cjid = strdup(jidnormalize(c->getdesc().nickname).c_str());
495 char *ctext = strdup(text.c_str());
497 xmlnode x = jutil_msgnew(TMSG_CHAT, cjid, 0, ctext);
499 if(ischannel(c)) {
500 xmlnode_put_attrib(x, "type", "groupchat");
501 if(!(cname = c->getdesc().nickname.substr(1)).empty())
502 xmlnode_put_attrib(x, "to", cname.c_str());
505 if(!enc.empty()) {
506 xmlnode xenc = xmlnode_insert_tag(x, "x");
507 xmlnode_put_attrib(xenc, "xmlns", "jabber:x:encrypted");
508 xmlnode_insert_cdata(xenc, enc.c_str(), (unsigned) -1);
511 if(conf->getourid(jhook.proto).additional["acknowledgements"] == "1") {
512 vector<agent>::iterator ia = find(jhook.agents.begin(),jhook.agents.end(), jhook.full_jids[cjid]);
513 if(ia != jhook.agents.end() && ia->params[agent::ptReceipts].enabled)
515 xmlnode request = xmlnode_insert_tag(x, "request");
516 xmlnode_put_attrib(request, "xmlns", NS_RECEIPTS);
519 #ifdef HAVE_SSTREAM
520 stringstream idstream;
521 idstream << ev.gettimestamp();
522 xmlnode_put_attrib(x, "id", idstream.str().c_str());
523 #else
524 strstream idstream;
525 idstream << ev.gettimestamp();
526 xmlnode_put_attrib(x, "id", idstream.str());
527 #endif
529 jab_send(jc, x);
530 xmlnode_free(x);
532 free (cjid);
533 free (ctext);
535 return true;
538 return false;
541 void jabberhook::sendnewuser(const imcontact &ic) {
542 sendnewuser(ic, true);
545 void jabberhook::removeuser(const imcontact &ic) {
546 removeuser(ic, true);
549 void jabberhook::sendnewuser(const imcontact &ic, bool report) {
550 xmlnode x, y, z;
551 icqcontact *c;
552 string cname;
554 if(!logged())
555 return;
557 if(!ischannel(ic)) {
558 char *cjid = strdup(jidnormalize(ic.nickname).c_str());
559 if(roster.find(cjid) != roster.end()) {
560 free (cjid);
561 return;
564 if(report) log(logContactAdd, ic.nickname.c_str());
566 x = jutil_presnew(JPACKET__SUBSCRIBE, cjid, 0);
567 jab_send(jc, x);
568 xmlnode_free(x);
570 x = jutil_iqnew(JPACKET__SET, NS_ROSTER);
571 xmlnode_put_attrib(x, "id", jab_getid(jc));
572 y = xmlnode_get_tag(x, "query");
573 z = xmlnode_insert_tag(y, "item");
574 xmlnode_put_attrib(z, "jid", cjid);
576 roster[cjid] = "";
578 if(c = clist.get(ic)) {
579 vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), c->getgroupid());
580 if(ig != groups.end()) {
581 z = xmlnode_insert_tag(z, "group");
582 xmlnode_insert_cdata(z, rusconv("ku", ig->getname()).c_str(), (unsigned) -1);
583 roster[cjid] = ig->getname();
587 jab_send(jc, x);
588 xmlnode_free(x);
590 if(c = clist.get(ic)) {
591 imcontact icc(jidtodisp(ic.nickname), proto);
592 if(ic.nickname != icc.nickname) {
593 c->setdesc(icc);
596 c->setnick("");
598 string u, h, r;
599 jidsplit(icc.nickname, u, h, r);
600 if (!u.empty())
601 c->setdispnick(u);
602 else
603 c->setdispnick(icc.nickname);
606 requestinfo(c);
608 free (cjid);
609 } else {
610 if(c = clist.get(ic)) {
611 cname = ic.nickname.substr(1);
613 if(!cname.empty()) {
614 cname += "/" + conf->getourid(proto).nickname;
616 char *ccname = strdup(cname.c_str());
617 char *ourjid = strdup(getourjid().c_str());
619 x = jutil_presnew(JPACKET__UNKNOWN, ccname, 0);
620 xmlnode_insert_cdata(xmlnode_insert_tag(x, "status"), "Online", (unsigned) -1);
622 free (ccname);
623 free (ourjid);
625 jab_send(jc, x);
626 xmlnode_free(x);
632 void jabberhook::removeuser(const imcontact &ic, bool report) {
633 xmlnode x, y, z;
634 icqcontact *c;
635 string cname;
637 if(!logged())
638 return;
640 if(!ischannel(ic)) {
641 char *cjid = strdup(jidnormalize(ic.nickname).c_str());
643 map<string, string>::iterator ir = roster.find(cjid);
645 if(ir == roster.end()) return;
646 else roster.erase(ir);
648 if(find(agents.begin(), agents.end(), cjid) != agents.end()) {
649 if(report) face.log(_("+ [jab] unregistering from the %s agent"), cjid);
651 x = jutil_iqnew(JPACKET__SET, NS_REGISTER);
652 xmlnode_put_attrib(x, "id", jab_getid(jc));
653 xmlnode_put_attrib(x, "to", cjid);
654 y = xmlnode_get_tag(x, "query");
655 xmlnode_insert_tag(y, "remove");
656 jab_send(jc, x);
657 xmlnode_free(x);
661 if(report) log(logContactRemove, ic.nickname.c_str());
663 x = jutil_presnew(JPACKET__UNSUBSCRIBE, cjid, 0);
664 jab_send(jc, x);
665 xmlnode_free(x);
667 x = jutil_iqnew(JPACKET__SET, NS_ROSTER);
668 xmlnode_put_attrib(x, "id", jab_getid(jc));
669 y = xmlnode_get_tag(x, "query");
670 z = xmlnode_insert_tag(y, "item");
671 xmlnode_put_attrib(z, "jid", cjid);
672 xmlnode_put_attrib(z, "subscription", "remove");
673 jab_send(jc, x);
674 xmlnode_free(x);
676 free (cjid);
678 } else {
679 if(c = clist.get(ic)) {
680 cname = ic.nickname.substr(1);
682 if(!cname.empty()) {
683 cname += "/" + conf->getourid(proto).nickname;
684 char *ccname = strdup(cname.c_str());
685 x = jutil_presnew(JPACKET__UNKNOWN, ccname, 0);
686 xmlnode_put_attrib(x, "type", "unavailable");
687 jab_send(jc, x);
688 xmlnode_free(x);
690 free(ccname);
692 map<string, vector<string> >::iterator icm = chatmembers.find(ic.nickname);
693 if(icm != chatmembers.end()) chatmembers.erase(icm);
699 void jabberhook::setautostatus(imstatus st) {
700 if(st != offline) {
701 if(getstatus() == offline) {
702 connect();
703 } else {
704 string msg;
706 switch(st) {
707 case dontdisturb:
708 case occupied:
709 case outforlunch:
710 case notavail:
711 msg = conf->getextstatus(proto, st); //external online status
712 if( msg.empty() ) msg = conf->getawaymsg(proto);
713 break;
714 case away:
715 msg = conf->getawaymsg(proto);
716 break;
717 case available:
718 case freeforchat:
719 msg = conf->getextstatus(proto, st); //external online status
722 setjabberstatus(ourstatus = st, msg);
724 } else {
725 if(getstatus() != offline) {
726 disconnect();
731 void jabberhook::requestinfo(const imcontact &ic) {
732 if(isconnecting() || logged()) {
733 vector<agent>::const_iterator ia = find(agents.begin(), agents.end(), ic.nickname);
735 if(ia != agents.end()) {
736 icqcontact *c = clist.get(imcontact(ic.nickname, proto));
737 if(c) {
738 c->setdispnick(ia->name);
739 c->setabout(ia->desc);
742 } else {
743 char *cjid = strdup(jidnormalize(ic.nickname).c_str());
744 xmlnode x = jutil_iqnew2(JPACKET__GET), y;//gtalk vCard request fix
745 xmlnode_put_attrib(x, "to", cjid);
746 xmlnode_put_attrib(x, "id", "VCARDreq");
747 y = xmlnode_insert_tag(x, "vCard");
748 xmlnode_put_attrib(y, "xmlns", NS_VCARD);
749 jab_send(jc, x);
750 xmlnode_free(x);
751 free (cjid);
757 void jabberhook::requestawaymsg(const imcontact &ic) {
758 icqcontact *c = clist.get(ic);
760 if(c) {
761 string am = awaymsgs[ic.nickname];
763 if(!am.empty()) {
764 em.store(imnotification(ic, (string) _("Away message:") + "\n\n" + rusconv("uk",am)));
765 } else {
766 face.log(_("+ [jab] no away message from %s, %s"),
767 c->getdispnick().c_str(), ic.totext().c_str());
772 imstatus jabberhook::getstatus() const {
773 return online() ? ourstatus : offline;
776 bool jabberhook::regnick(const string &nick, const string &pass,
777 const string &serv, string &err) {
778 int pos, port;
779 string jid = nick + "@" + serv;
781 if((pos = jid.find(":")) != -1) {
782 port = atoi(jid.substr(pos+1).c_str());
783 jid.erase(pos);
784 } else {
785 port = icqconf::defservers[proto].port;
788 regmode = true;
790 /* TODO: do these really need to be copied ??? */
791 char *cjid = strdup(jid.c_str());
792 char *cpass = strdup(pass.c_str());
793 char *cserver = strdup(serv.c_str());
795 jc = jab_new(cjid, cpass, cserver, port, 0);
797 free (cjid);
798 free (cpass);
799 free (cserver);
801 if(!jc->user) {
802 err = _("Wrong nickname given, cannot register");
803 fonline = false;
804 return false;
807 jab_packet_handler(jc, &packethandler);
808 jab_state_handler(jc, &statehandler);
810 if(conf->getdebug())
811 jab_logger(jc, &jlogger);
813 jc->cw_state = CW_CONNECT_BLOCKING;
814 jab_start(jc);
816 if(jc) id = atoi(jab_reg(jc));
818 if(!online()) {
819 err = _("Unable to connect");
821 } else {
822 regdone = false;
823 regerr = "";
825 while(online() && !regdone && regerr.empty()) {
826 main();
829 disconnect();
830 err = regdone ? "" : regerr;
833 return regdone;
836 void jabberhook::setjabberstatus(imstatus st, string msg) {
837 xmlnode x = jutil_presnew(JPACKET__UNKNOWN, 0, 0);
839 switch(st) {
840 case away:
841 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "away", (unsigned) -1);
842 break;
844 case occupied:
845 case dontdisturb:
846 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "dnd", (unsigned) -1);
847 break;
849 case freeforchat:
850 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "chat", (unsigned) -1);
851 break;
853 case outforlunch:
854 case notavail:
855 xmlnode_insert_cdata(xmlnode_insert_tag(x, "show"), "xa", (unsigned) -1);
856 break;
858 case invisible:
859 xmlnode_put_attrib(x, "type", "invisible");
860 break;
862 case offline:
863 xmlnode_put_attrib(x, "type", "unavailable");
864 break;
868 map<string, string> add = conf->getourid(proto).additional;
870 if(!add["prio"].empty())
871 xmlnode_insert_cdata(xmlnode_insert_tag(x, "priority"),
872 add["prio"].c_str(), (unsigned) -1);
874 if(msg.empty())
875 msg = imstatus2str(st);
876 int pos = 0;
877 while( (pos = msg.find( '\r' )) != string::npos ) {
878 if( msg[pos+1] == '\n' ) {
879 msg.erase(pos, 1);
880 } else {
881 msg.replace(pos, 1, "\n");
885 xmlnode_insert_cdata(xmlnode_insert_tag(x, "status"),
886 rusconv("ku", msg).c_str(), (unsigned) -1);
888 //check if our avatar changed and send update request
889 icqcontact *ic = clist.get(contactroot);
890 icqcontact::basicinfo bi = ic->getbasicinfo();
892 if(!bi.avatar.empty())
894 string my_avatar_hash;
895 if( get_my_avatar_hash(my_avatar_hash) )
897 xmlnode y = xmlnode_insert_tag(x, "x");
898 xmlnode_put_attrib(y, "xmlns", NS_VCARDUP);
899 xmlnode z = xmlnode_insert_tag(y, "photo");
900 xmlnode_insert_cdata(z, my_avatar_hash.c_str(), (unsigned) -1);
904 #ifdef HAVE_GPGME
906 if(!add["pgpkey"].empty()) {
907 pgp.clearphrase(proto);
908 xmlnode sign = xmlnode_insert_tag(x, "x");
909 xmlnode_put_attrib(sign, "xmlns", "jabber:x:signed");
910 xmlnode_insert_cdata(sign, pgp.sign(msg, add["pgpkey"], proto).c_str(), (unsigned) -1);
913 #endif
915 jab_send(jc, x);
916 xmlnode_free(x);
918 sendvisibility();
920 logger.putourstatus(proto, getstatus(), ourstatus = st);
923 void jabberhook::sendvisibility() {
924 xmlnode x;
925 icqlist::iterator i;
927 for(i = lst.begin(); i != lst.end(); ++i)
928 if(i->getdesc().pname == proto) {
929 x = jutil_presnew(JPACKET__UNKNOWN, 0, 0);
930 xmlnode_put_attrib(x, "to", jidnormalize(i->getdesc().nickname).c_str());
932 if(i->getstatus() == csvisible && ourstatus == invisible) {
934 } else if(i->getstatus() == csvisible && ourstatus != invisible) {
936 } else if(i->getstatus() == csinvisible && ourstatus == invisible) {
938 } else if(i->getstatus() == csinvisible && ourstatus != invisible) {
939 xmlnode_put_attrib(x, "type", "unavailable");
943 jab_send(jc, x);
944 xmlnode_free(x);
948 vector<string> jabberhook::getservices(servicetype::enumeration st) const {
949 vector<agent>::const_iterator ia = agents.begin();
950 vector<string> r;
952 agent::param_type pt;
954 switch(st) {
955 case servicetype::search:
956 pt = agent::ptSearch;
957 break;
958 case servicetype::registration:
959 pt = agent::ptRegister;
960 break;
961 case servicetype::groupchat:
962 while(ia != agents.end()) {
963 if(ia->type == agent::atGroupchat) r.push_back(ia->jid);
964 ++ia;
966 default:
967 return r;
970 while(ia != agents.end()) {
971 if(ia->params[pt].enabled)
972 r.push_back(ia->name);
973 ++ia;
976 return r;
979 vector<pair<string, string> > jabberhook::getservparams(const string &agentname, agent::param_type pt) const {
980 vector<agent>::const_iterator ia = agents.begin();
982 while(ia != agents.end()) {
983 if(ia->name == agentname)
984 if(ia->params[pt].enabled)
985 return ia->params[pt].paramnames;
987 ++ia;
990 return vector<pair<string, string> >();
993 vector<pair<string, string> > jabberhook::getsearchparameters(const string &agentname) const {
994 return getservparams(agentname, agent::ptSearch);
997 vector<pair<string, string> > jabberhook::getregparameters(const string &agentname) const {
998 return getservparams(agentname, agent::ptRegister);
1001 void jabberhook::gotagentinfo(xmlnode x) {
1002 xmlnode y;
1003 string name, data, ns;
1004 //agent::param_type pt;
1005 vector<agent>::iterator ia = jhook.agents.begin();
1006 const char *from = xmlnode_get_attrib(x, "from"), *p, *q;
1008 if(!from) return;
1010 while(ia != jhook.agents.end()) {
1011 if(ia->jid == from)
1012 if(y = xmlnode_get_tag(x, "query")) {
1013 p = xmlnode_get_attrib(y, "xmlns"); if(p) ns = p;
1014 if (ns == NS_DISCOINFO) {
1015 for(y = xmlnode_get_firstchild(y); y; y = xmlnode_get_nextsibling(y)) {
1016 p = xmlnode_get_name(y); name = p ? p : "";
1017 if (name == "identity") {
1018 if (q = xmlnode_get_attrib(y, "name"))
1019 ia->desc = q;
1020 if (q = (xmlnode_get_attrib(y, "category"))) {
1021 data = q;
1022 if (data == "conference") {
1023 ia->type = agent::atGroupchat;
1024 } else if (data == "gateway") {
1025 ia->type = agent::atTransport;
1028 } else if (name == "feature") {
1029 if ((q = xmlnode_get_attrib(y, "var")) && (!strcmp(q, NS_SEARCH))) { // can do search, ask for parameters
1030 ia->params[agent::ptSearch].enabled = true;
1031 ia->params[agent::ptSearch].paramnames.clear();
1032 xmlnode z = jutil_iqnew(JPACKET__GET, NS_SEARCH);
1033 char *id = jab_getid(jc);
1034 ignore_ids.insert((string)id);
1035 xmlnode_put_attrib(z, "id", id);
1036 xmlnode_put_attrib(z, "to", from);
1037 jab_send(jc, z);
1038 xmlnode_free(z);
1039 } else if ((q = xmlnode_get_attrib(y, "var")) && (!strcmp(q, NS_RECEIPTS))) {
1040 ia->params[agent::ptReceipts].enabled = true;
1044 break;
1045 } else if (ns == NS_SEARCH) { // probably agent info with jabber:iq:search
1046 for(y = xmlnode_get_firstchild(y); y; y = xmlnode_get_nextsibling(y)) {
1047 p = xmlnode_get_name(y); name = p ? p : "";
1048 p = xmlnode_get_data(y); data = p ? p : "";
1049 if (name == "item") // it's probably not answer with parameters
1050 break;
1051 if (name == "instructions") {
1052 ia->params[agent::ptSearch].instruction = data;
1053 } else if ((name == "x") && (NSCHECK(y, "jabber:x:data"))) {
1054 continue;
1055 } else if (name == "key") {
1056 ia->params[agent::ptSearch].key = data;
1057 } else {
1058 ia->params[agent::ptSearch].paramnames.push_back(make_pair(name, data));
1061 if ((name != "item") && ia->params[agent::ptSearch].paramnames.empty())
1062 agents.erase(ia);
1063 break;
1066 ++ia;
1070 while(ia != jhook.agents.end()) {
1071 if(ia->jid == from)
1072 if(y = xmlnode_get_tag(x, "query")) {
1073 p = xmlnode_get_attrib(y, "xmlns"); if(p) ns = p;
1075 if(ns == NS_SEARCH) pt = agent::ptSearch; else
1076 if(ns == NS_REGISTER) pt = agent::ptRegister; else
1077 break;
1079 ia->params[pt].enabled = true;
1080 ia->params[pt].paramnames.clear();
1082 for(y = xmlnode_get_firstchild(y); y; y = xmlnode_get_nextsibling(y)) {
1083 p = xmlnode_get_name(y); name = p ? p : "";
1084 p = xmlnode_get_data(y); data = p ? p : "";
1086 if(name == "instructions") ia->params[pt].instruction = data; else
1087 if(name == "key") ia->params[pt].key = data; else
1088 if(!name.empty() && name != "registered") {
1089 ia->params[pt].paramnames.push_back(make_pair(name, data));
1093 if(ia->params[pt].paramnames.empty()) agents.erase(ia);
1094 break;
1096 ++ia;
1101 void jabberhook::lookup(const imsearchparams &params, verticalmenu &dest) {
1102 xmlnode x, y;
1104 searchdest = &dest;
1106 while(!foundguys.empty()) {
1107 delete foundguys.back();
1108 foundguys.pop_back();
1111 if(!params.service.empty()) {
1112 x = jutil_iqnew(JPACKET__SET, NS_SEARCH);
1113 xmlnode_put_attrib(x, "id", "Lookup");
1115 y = xmlnode_get_tag(x, "query");
1117 vector<agent>::const_iterator ia = agents.begin();
1118 while(ia != agents.end()) {
1119 if(ia->name == params.service) {
1120 xmlnode_put_attrib(x, "to", ia->jid.c_str());
1121 xmlnode_insert_cdata(xmlnode_insert_tag(y, "key"),
1122 ia->params[agent::atSearch].key.c_str(), (unsigned int) -1);
1123 break;
1125 ++ia;
1128 vector<pair<string, string> >::const_iterator ip = params.flexparams.begin();
1129 while(ip != params.flexparams.end()) {
1130 xmlnode_insert_cdata(xmlnode_insert_tag(y,
1131 ip->first.c_str()), ip->second.c_str(), (unsigned int) -1);
1132 ++ip;
1135 jab_send(jc, x);
1136 xmlnode_free(x);
1138 } else if(!params.room.empty()) {
1139 icqcontact *c;
1140 string room = params.room.substr(1);
1142 if(c = clist.get(imcontact(params.room, proto))) {
1143 vector<string>::const_iterator im = chatmembers[room].begin();
1144 while(im != chatmembers[room].end()) {
1145 foundguys.push_back(c = new icqcontact(imcontact(*im, proto)));
1146 searchdest->additem(conf->getcolor(cp_clist_jabber), c, (string) " " + *im);
1147 ++im;
1151 face.findready();
1152 log(logConfMembers, foundguys.size());
1154 searchdest->redraw();
1155 searchdest = 0;
1159 void jabberhook::renamegroup(const string &oldname, const string &newname) {
1160 map<string, string>::iterator ir = roster.begin();
1162 while(ir != roster.end()) {
1163 if(ir->second == oldname) {
1164 icqcontact *c = clist.get(imcontact(jidtodisp(ir->first), proto));
1165 if(c) {
1166 updatecontact(c);
1167 ir->second = newname;
1171 ++ir;
1175 void jabberhook::ouridchanged(const icqconf::imaccount &ia) {
1176 if(logged()) {
1177 setautostatus(ourstatus);
1178 // send a new presence
1182 // ----------------------------------------------------------------------------
1184 void jabberhook::gotsearchresults(xmlnode x) {
1185 xmlnode y, z;
1186 const char *jid, *nick, *first, *last, *email;
1187 icqcontact *c;
1189 if(!searchdest)
1190 return;
1192 if(y = xmlnode_get_tag(x, "query"))
1193 for(y = xmlnode_get_tag(y, "item"); y; y = xmlnode_get_nextsibling(y)) {
1194 jid = xmlnode_get_attrib(y, "jid");
1195 nick = first = last = email = 0;
1197 z = xmlnode_get_tag(y, "nick"); if(z) nick = xmlnode_get_data(z);
1198 z = xmlnode_get_tag(y, "first"); if(z) first = xmlnode_get_data(z);
1199 z = xmlnode_get_tag(y, "last"); if(z) last = xmlnode_get_data(z);
1200 z = xmlnode_get_tag(y, "email"); if(z) email = xmlnode_get_data(z);
1202 if(jid) {
1203 c = new icqcontact(imcontact(jidnormalize(jid), proto));
1204 icqcontact::basicinfo cb = c->getbasicinfo();
1206 if(nick) {
1207 c->setnick(nick);
1208 c->setdispnick(c->getnick());
1211 if(first) cb.fname = first;
1212 if(last) cb.lname = last;
1213 if(email) cb.email = email;
1214 c->setbasicinfo(cb);
1216 foundguys.push_back(c);
1218 string line = (string) " " + c->getnick();
1219 if(line.size() > 12) line.resize(12);
1220 else line += string(12-line.size(), ' ');
1221 line += " " + cb.fname + " " + cb.lname;
1222 if(!cb.email.empty()) line += " <" + cb.email + ">";
1224 searchdest->additem(conf->getcolor(cp_clist_jabber), c, line);
1228 face.findready();
1230 log(logSearchFinished, foundguys.size());
1232 searchdest->redraw();
1233 searchdest = 0;
1236 void jabberhook::gotloggedin() {
1237 xmlnode x, y;
1239 flogged = true;
1241 // x = jutil_iqnew(JPACKET__GET, NS_AGENTS);
1242 // xmlnode_put_attrib(x, "id", "Agent List");
1243 // jab_send(jc, x);
1244 // xmlnode_free(x);
1246 char *server = strdup(jc->user->server);
1248 jhook.agents.push_back(agent(server, server, "", agent::atUnknown));
1250 char *id;
1251 x = jutil_iqnew(JPACKET__GET, NS_DISCOINFO);
1252 id = jab_getid(jc);
1253 ignore_ids.insert((string)id);
1254 xmlnode_put_attrib(x, "id", id);
1255 xmlnode_put_attrib(x, "to", server);
1256 jab_send(jc, x);
1257 xmlnode_free(x);
1259 x = jutil_iqnew(JPACKET__GET, NS_DISCOITEMS);
1260 id = jab_getid(jc);
1261 ignore_ids.insert((string)id);
1262 xmlnode_put_attrib(x, "id", id);
1263 xmlnode_put_attrib(x, "to", server);
1264 jab_send(jc, x);
1265 xmlnode_free(x);
1266 free(server);
1269 x = jutil_iqnew(JPACKET__GET, NS_ROSTER);
1270 xmlnode_put_attrib(x, "id", "Roster");
1271 jab_send(jc, x);
1272 xmlnode_free(x);
1275 void jabberhook::gotroster(xmlnode x) {
1276 xmlnode y, z;
1277 imcontact ic;
1278 icqcontact *c;
1279 string grp;
1281 for(y = xmlnode_get_tag(x, "item"); y; y = xmlnode_get_nextsibling(y)) {
1282 const char *alias = xmlnode_get_attrib(y, "jid");
1283 const char *sub = xmlnode_get_attrib(y, "subscription");
1284 const char *name = xmlnode_get_attrib(y, "name");
1285 const char *group = 0;
1287 z = xmlnode_get_tag(y, "group");
1288 if(z) group = xmlnode_get_data(z);
1289 grp = group ? rusconv("uk", group) : "";
1291 if(alias) {
1292 ic = imcontact(jidtodisp(alias), proto);
1293 clist.updateEntry(ic, grp);
1295 if(c = clist.get(ic)) {
1296 if(name) c->setdispnick(rusconv("uk", name)); else {
1297 string u, h, r;
1298 jidsplit(alias, u, h, r);
1299 if (!u.empty())
1300 c->setdispnick(u);
1301 else
1302 c->setdispnick(jidtodisp(alias));
1306 roster[jidnormalize(alias)] = grp;
1310 postlogin();
1313 void jabberhook::postlogin() {
1314 int i;
1315 icqcontact *c;
1317 ourstatus = available;
1318 time(&timer_keepalive);
1320 log(logLogged);
1321 setautostatus(jhook.manualstatus);
1322 face.update();
1324 for(i = 0; i < clist.count; i++) {
1325 c = (icqcontact *) clist.at(i);
1327 if(c->getdesc().pname == proto)
1328 if(ischannel(c))
1329 if(c->getbasicinfo().requiresauth)
1330 c->setstatus(available);
1333 agents.insert(agents.begin(), agent("vcard", "Jabber VCard", "", agent::atStandard));
1334 agents.begin()->params[agent::ptRegister].enabled = true;
1336 string buf;
1337 ifstream f(conf->getconfigfname("jabber-infoset").c_str());
1339 if(f.is_open()) {
1340 icqcontact *c = clist.get(contactroot);
1342 c->clear();
1343 icqcontact::basicinfo bi = c->getbasicinfo();
1344 icqcontact::reginfo ri = c->getreginfo();
1346 ri.service = agents.begin()->name;
1347 getstring(f, buf); c->setnick(buf);
1348 getstring(f, buf); bi.email = buf;
1349 getstring(f, buf); bi.fname = buf;
1350 getstring(f, buf); bi.lname = buf;
1351 f.close();
1353 c->setbasicinfo(bi);
1354 c->setreginfo(ri);
1356 sendupdateuserinfo(*c);
1357 unlink(conf->getconfigfname("jabber-infoset").c_str());
1361 void jabberhook::conferencecreate(const imcontact &confid, const vector<imcontact> &lst) {
1362 char *jcid = strdup(confid.nickname.substr(1).c_str());
1363 xmlnode x = jutil_presnew(JPACKET__UNKNOWN, jcid, 0);
1364 jab_send(jc, x);
1365 xmlnode_free(x);
1366 free (jcid);
1369 void jabberhook::vcput(xmlnode x, const string &name, const string &val) {
1370 xmlnode_insert_cdata(xmlnode_insert_tag(x, name.c_str()),
1371 jhook.rusconv("ku", val).c_str(), (unsigned int) -1);
1374 void jabberhook::vcputphone(xmlnode x, const string &type, const string &place, const string &number) {
1375 xmlnode z = xmlnode_insert_tag(x, "TEL");
1376 vcput(z, type, "");
1377 vcput(z, place, "");
1378 vcput(z, "NUMBER", number);
1381 void jabberhook::vcputaddr(xmlnode x, const string &place, const string &street,
1382 const string &locality, const string &region, const string &pcode,
1383 unsigned short country) {
1384 xmlnode z = xmlnode_insert_tag(x, "ADR");
1385 vcput(z, place, "");
1386 vcput(z, "STREET", street);
1387 vcput(z, "LOCALITY", locality);
1388 vcput(z, "REGION", region);
1389 vcput(z, "PCODE", pcode);
1390 vcput(z, "CTRY", getCountryIDtoString(country));
1393 void jabberhook::vcputavatar(xmlnode x, const string &type, const string &val) {
1394 xmlnode z = xmlnode_insert_tag(x, "PHOTO");
1395 vcput(z, "TYPE", type);
1396 xmlnode_insert_cdata(xmlnode_insert_tag(z, "BINVAL"), val.c_str(), (unsigned int) -1);
1399 void jabberhook::sendupdateuserinfo(const icqcontact &c) {
1400 xmlnode x, y, z;
1401 icqcontact::reginfo ri = c.getreginfo();
1402 string buf;
1403 char cbuf[64];
1405 vector<agent>::const_iterator ia = agents.begin();
1407 while(ia != agents.end()) {
1408 if(ia->name == ri.service) {
1409 if(ia->type == agent::atStandard) {
1410 x = jutil_iqnew2(JPACKET__SET);//vCard w/o trash query tag in vcard
1411 xmlnode_put_attrib(x, "id", jab_getid(jc));
1412 y = xmlnode_insert_tag(x, "vCard");
1413 xmlnode_put_attrib(y, "xmlns", NS_VCARD);
1414 xmlnode_put_attrib(y, "version", "3.0");
1416 icqcontact::basicinfo bi = c.getbasicinfo();
1417 icqcontact::moreinfo mi = c.getmoreinfo();
1418 icqcontact::workinfo wi = c.getworkinfo();
1419 conf->setavatar(proto, bi.avatar); //saving avatar path to file
1421 vcput(y, "DESC", c.getabout());
1422 vcput(y, "EMAIL", bi.email);
1423 vcput(y, "URL", mi.homepage);
1424 vcput(y, "TITLE", wi.position);
1425 vcput(y, "AGE", i2str(mi.age));
1426 vcput(y, "NICKNAME", c.getnick());
1428 vcput(y, "GENDER",
1429 mi.gender == genderMale ? "Male" :
1430 mi.gender == genderFemale ? "Female" : "");
1432 if(mi.birth_year && mi.birth_month && mi.birth_day) {
1433 snprintf(cbuf, sizeof(cbuf), "%04d-%02d-%02d", mi.birth_year, mi.birth_month, mi.birth_day);
1434 vcput(y, "BDAY", cbuf);
1437 if(!(buf = bi.fname).empty()) buf += " " + bi.lname;
1438 vcput(y, "FN", buf);
1440 z = xmlnode_insert_tag(y, "N");
1441 vcput(z, "GIVEN", bi.fname);
1442 vcput(z, "FAMILY", bi.lname);
1444 z = xmlnode_insert_tag(y, "ORG");
1445 vcput(z, "ORGNAME", wi.company);
1446 vcput(z, "ORGUNIT", wi.dept);
1448 vcputphone(y, "VOICE", "HOME", bi.phone);
1449 vcputphone(y, "FAX", "HOME", bi.fax);
1450 vcputphone(y, "VOICE", "WORK", wi.phone);
1451 vcputphone(y, "FAX", "WORK", wi.fax);
1453 vcputaddr(y, "HOME", bi.street, bi.city, bi.state, bi.zip, bi.country);
1454 vcputaddr(y, "WORK", wi.street, wi.city, wi.state, wi.zip, wi.country);
1456 vcput(y, "HOMECELL", bi.cellular);
1457 vcput(y, "WORKURL", wi.homepage);
1459 string avatar, image_type;
1460 if( get_base64_avatar(image_type, avatar) )
1461 vcputavatar(y, image_type, avatar);
1463 } else {
1464 x = jutil_iqnew(JPACKET__SET, NS_REGISTER);
1465 xmlnode_put_attrib(x, "id", "Register");
1466 y = xmlnode_get_tag(x, "query");
1468 xmlnode_put_attrib(x, "to", ia->jid.c_str());
1469 xmlnode_insert_cdata(xmlnode_insert_tag(y, "key"),
1470 ia->params[agent::ptRegister].key.c_str(), (unsigned int) -1);
1472 vector<pair<string, string> >::const_iterator ip = ri.params.begin();
1473 while(ip != ri.params.end()) {
1474 xmlnode_insert_cdata(xmlnode_insert_tag(y,
1475 ip->first.c_str()), ip->second.c_str(), (unsigned int) -1);
1476 ++ip;
1481 jab_send(jc, x);
1482 xmlnode_free(x);
1483 break;
1485 ++ia;
1489 void jabberhook::gotmessage(const string &type, const string &from, const string &abody, const string &enc) {
1490 string u, h, r, body(abody);
1491 jidsplit(from, u, h, r);
1493 imcontact ic(jidtodisp(from), proto), chic;
1495 if(clist.get(chic = imcontact((string) "#" + ic.nickname, proto))) {
1496 ic = chic;
1497 if(!r.empty()) body.insert(0, r + ": ");
1500 #ifdef HAVE_GPGME
1501 icqcontact *c = clist.get(ic);
1503 if(c) {
1504 if(!enc.empty()) {
1505 c->setusepgpkey(true);
1506 if(pgp.enabled(proto)) {
1507 body = pgp.decrypt(enc, proto);
1508 if (body.empty()) // probably decryption error, store at least encrypted message
1509 body = enc;
1511 else c->setusepgpkey(false);
1512 } else {
1513 c->setusepgpkey(false);
1516 #endif
1518 #ifdef HAVE_LIBOTR
1519 if (!otr.receive_message(proto, from, body)) return;
1520 #endif
1522 em.store(immessage(ic, imevent::incoming, rusconv("uk", body)));
1525 void jabberhook::updatecontact(icqcontact *c) {
1526 xmlnode x, y;
1528 if(logged()) {
1529 char *cjid = strdup(jidnormalize(c->getdesc().nickname).c_str());
1530 char *cname = strdup(rusconv("ku", c->getdispnick()).c_str());
1532 x = jutil_iqnew(JPACKET__SET, NS_ROSTER);
1533 xmlnode_put_attrib(x, "id", jab_getid(jc));
1534 y = xmlnode_insert_tag(xmlnode_get_tag(x, "query"), "item");
1535 xmlnode_put_attrib(y, "jid", cjid);
1536 xmlnode_put_attrib(y, "name", cname);
1538 vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), c->getgroupid());
1539 if(ig != groups.end()) {
1540 y = xmlnode_insert_tag(y, "group");
1541 xmlnode_insert_cdata(y, rusconv("ku", ig->getname()).c_str(), (unsigned) -1);
1544 jab_send(jc, x);
1545 xmlnode_free(x);
1546 free (cjid);
1547 free (cname);
1551 void jabberhook::gotvcard(const imcontact &ic, xmlnode v) {
1552 xmlnode ad, n;
1553 char *p;
1554 string name, data;
1555 bool wasrole = false;
1557 icqcontact *c = clist.get(ic);
1558 if(!c || isourid(ic.nickname)) c = clist.get(contactroot);
1560 if(c) {
1561 icqcontact::basicinfo bi = c->getbasicinfo();
1562 icqcontact::moreinfo mi = c->getmoreinfo();
1563 icqcontact::workinfo wi = c->getworkinfo();
1565 for(ad = xmlnode_get_firstchild(v); ad; ad = xmlnode_get_nextsibling(ad)) {
1566 p = xmlnode_get_name(ad); name = p ? up(p) : "";
1567 p = xmlnode_get_data(ad); data = p ? rusconv("uk", p) : "";
1569 if(name == "NICKNAME") c->setnick(data); else
1570 if(name == "DESC") c->setabout(data); else
1571 if(name == "EMAIL") bi.email = data; else
1572 if(name == "URL") mi.homepage = data; else
1573 if(name == "AGE") mi.age = atoi(data.c_str()); else
1574 if(name == "HOMECELL") bi.cellular = data; else
1575 if(name == "WORKURL") wi.homepage = data; else
1576 if(name == "GENDER") {
1577 if(data == "Male") mi.gender = genderMale; else
1578 if(data == "Female") mi.gender = genderFemale; else
1579 mi.gender = genderUnspec;
1580 } else
1581 if(name == "TITLE" || name == "ROLE") {
1582 if(!wasrole) {
1583 wasrole = true;
1584 wi.position = "";
1587 if(!wi.position.empty()) wi.position += " / ";
1588 wi.position += data;
1589 } else
1590 if(name == "FN") {
1591 bi.fname = getword(data);
1592 bi.lname = data;
1593 } else
1594 if(name == "BDAY") {
1595 mi.birth_year = atoi(getword(data, "-").c_str());
1596 mi.birth_month = atoi(getword(data, "-").c_str());
1597 mi.birth_day = atoi(getword(data, "-").c_str());
1598 } else
1599 if(name == "ORG") {
1600 if(p = xmlnode_get_tag_data(ad, "ORGNAME")) wi.company = rusconv("uk", p);
1601 if(p = xmlnode_get_tag_data(ad, "ORGUNIT")) wi.dept = rusconv("uk", p);
1602 } else
1603 if(name == "N") {
1604 if(p = xmlnode_get_tag_data(ad, "GIVEN")) bi.fname = rusconv("uk", p);
1605 if(p = xmlnode_get_tag_data(ad, "FAMILY")) bi.lname = rusconv("uk", p);
1606 } else
1607 if(name == "ADR") {
1608 if(xmlnode_get_tag(ad, "HOME")) {
1609 if(p = xmlnode_get_tag_data(ad, "STREET")) bi.street = rusconv("uk", p);
1610 if(p = xmlnode_get_tag_data(ad, "LOCALITY")) bi.city = rusconv("uk", p);
1611 if(p = xmlnode_get_tag_data(ad, "REGION")) bi.state = rusconv("uk", p);
1612 if(p = xmlnode_get_tag_data(ad, "PCODE")) bi.zip = rusconv("uk", p);
1614 if((p = xmlnode_get_tag_data(ad, "CTRY"))
1615 || (p = xmlnode_get_tag_data(ad, "COUNTRY")))
1616 bi.country = getCountryByName(p);
1618 } else if(xmlnode_get_tag(ad, "WORK")) {
1619 if(p = xmlnode_get_tag_data(ad, "STREET")) wi.street = rusconv("uk", p);
1620 if(p = xmlnode_get_tag_data(ad, "LOCALITY")) wi.city = rusconv("uk", p);
1621 if(p = xmlnode_get_tag_data(ad, "REGION")) wi.state = rusconv("uk", p);
1622 if(p = xmlnode_get_tag_data(ad, "PCODE")) wi.zip = rusconv("uk", p);
1624 if((p = xmlnode_get_tag_data(ad, "CTRY"))
1625 || (p = xmlnode_get_tag_data(ad, "COUNTRY")))
1626 wi.country = getCountryByName(p);
1628 } else
1629 if(name == "TEL") {
1630 if(p = xmlnode_get_tag_data(ad, "NUMBER")) {
1631 if(xmlnode_get_tag(ad, "VOICE")) {
1632 if(xmlnode_get_tag(ad, "HOME")) bi.phone = rusconv("uk", p); else
1633 if(xmlnode_get_tag(ad, "WORK")) wi.phone = rusconv("uk", p);
1635 } else if(xmlnode_get_tag(ad, "FAX")) {
1636 if(xmlnode_get_tag(ad, "HOME")) bi.fax = rusconv("uk", p); else
1637 if(xmlnode_get_tag(ad, "WORK")) wi.fax = rusconv("uk", p);
1641 else if( name == "PHOTO" )//get and write user avatar
1643 if(!isourid(ic.nickname)) {
1644 string contact_dir = c->getdirname() + "avatar";
1645 if(p = xmlnode_get_tag_data(ad, "TYPE"))
1648 string ext;
1649 if( get_img_ext(p, ext) )
1651 contact_dir += (string)"." + ext;
1652 if(p = xmlnode_get_tag_data(ad, "BINVAL")) {
1653 int len;
1654 char *ptr = base64_decode( p, &len );
1655 if( ptr )
1657 int ggg = open(contact_dir.c_str(), O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
1658 if( ggg >= 0 )
1660 write(ggg, ptr, len);
1661 close(ggg);
1662 if( justpathname( bi.avatar ).empty() )
1663 bi.avatar = c->getdirname() + bi.avatar;
1664 if( (contact_dir != bi.avatar) && !bi.avatar.empty() ) //clear old avatar
1665 unlink(bi.avatar.c_str());
1666 bi.avatar = "avatar." + ext;
1668 free(ptr);
1677 if(isourid(ic.nickname)) {//fill configuration window
1678 map<string, string> add = conf->getourid(proto).additional;
1679 if(!add["avatar"].empty()) {
1680 bi.avatar = add["avatar"];
1683 c->setbasicinfo(bi);
1684 c->setmoreinfo(mi);
1685 c->setworkinfo(wi);
1687 if(isourid(ic.nickname)) {
1688 icqcontact *cc = clist.get(ic);
1689 if(cc) {
1690 cc->setnick(c->getnick());
1691 cc->setabout(c->getabout());
1692 cc->setbasicinfo(bi);
1693 cc->setmoreinfo(mi);
1694 cc->setworkinfo(wi);
1698 xmlnode_free(v); //without it very HUGE memory leaks on some accounts
1701 void jabberhook::requestversion(const imcontact &ic)
1703 string cjid_str = ic.nickname;
1704 transform(cjid_str.begin(), cjid_str.end(), cjid_str.begin(), ::tolower);
1706 xmlnode x = jutil_iqnew(JPACKET__GET, NS_VERSION);
1708 xmlnode_put_attrib(x, "to", jhook.full_jids[cjid_str].c_str());
1709 xmlnode_put_attrib(x, "id", "versionreq");
1710 xmlnode_put_attrib(x, "from", getourjid().c_str());
1711 jab_send(jc, x);
1712 xmlnode_free(x);
1715 void jabberhook::sendversion(const imcontact &ic, xmlnode i) {
1716 string id;
1717 char *p = xmlnode_get_attrib(i, "id"); if(p) id = p; else id = "versionreq";
1718 string cjid_str = ic.nickname;
1719 transform(cjid_str.begin(), cjid_str.end(), cjid_str.begin(), ::tolower);
1720 const char *cjid = jhook.full_jids[cjid_str].c_str();
1721 xmlnode x = jutil_iqnew(JPACKET__RESULT, NS_VERSION), y;
1722 xmlnode_put_attrib(x, "to", cjid);
1724 xmlnode_put_attrib(x, "from", getourjid().c_str());
1725 xmlnode_put_attrib(x, "id", id.c_str() );
1726 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "name");
1727 xmlnode_insert_cdata(y, PACKAGE, (unsigned) -1 );
1728 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "version");
1729 xmlnode_insert_cdata(y, centerim::version, (unsigned) -1 );
1730 #ifdef HAVE_UNAME
1731 if(conf->getourid(jhook.proto).additional["osinfo"] == "1")
1733 struct utsname buf;
1734 if( !uname( &buf ) )
1736 string os = buf.sysname;
1737 os += " ";
1738 os += buf.release;
1739 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "os");
1740 xmlnode_insert_cdata(y, os.c_str(), (unsigned) -1 );
1743 #endif
1744 jab_send(jc, x);
1745 xmlnode_free(x);
1748 void jabberhook::gotversion(const imcontact &ic, xmlnode x) { //fix version parsing
1749 xmlnode y = xmlnode_get_tag(x, "query"), z;
1750 char *p;
1751 string vinfo;
1752 if(y) {
1753 if(z = xmlnode_get_tag(y, "name"))
1754 if(p = xmlnode_get_data(z))
1756 if(p) vinfo = rusconv("uk", p);
1759 if(z = xmlnode_get_tag(y, "version"))
1760 if(p = xmlnode_get_data(z)) {
1761 if(!vinfo.empty()) vinfo += ", ";
1762 vinfo += rusconv("uk", p);
1765 if(z = xmlnode_get_tag(y, "os"))
1766 if(p = xmlnode_get_data(z)) {
1767 if(!vinfo.empty()) vinfo += " / ";
1768 vinfo += rusconv("uk", p);
1771 char buf[NOTIFBUF];
1772 snprintf(buf, NOTIFBUF, _("The remote is using %s"), vinfo.c_str());
1773 em.store(imnotification(ic, buf));
1777 void jabberhook::senddiscoinfo(const imcontact &ic, xmlnode i) {
1778 string id;
1779 char *p = xmlnode_get_attrib(i, "id"); if(p) id = p; else id = "discoinfo";
1780 string cjid_str = ic.nickname;
1781 transform(cjid_str.begin(), cjid_str.end(), cjid_str.begin(), ::tolower);
1782 const char *cjid = jhook.full_jids[cjid_str].c_str();
1783 xmlnode x = jutil_iqnew(JPACKET__RESULT, NS_DISCOINFO), y;
1784 xmlnode_put_attrib(x, "to", cjid);
1785 xmlnode_put_attrib(x, "from", getourjid().c_str());
1786 xmlnode_put_attrib(x, "id", id.c_str() );
1788 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "identity");
1789 xmlnode_put_attrib(y, "category", "client");
1790 xmlnode_put_attrib(y, "type", "pc");
1791 xmlnode_put_attrib(y, "name", "centerim");
1793 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1794 xmlnode_put_attrib(y, "var", NS_DISCOINFO);
1796 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1797 xmlnode_put_attrib(y, "var", NS_VERSION);
1799 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1800 xmlnode_put_attrib(y, "var", NS_VCARD);
1802 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1803 xmlnode_put_attrib(y, "var", NS_VCARDUP);
1805 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1806 xmlnode_put_attrib(y, "var", NS_OOB );
1808 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1809 xmlnode_put_attrib(y, "var", NS_BYTESTREAMS );
1811 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1812 xmlnode_put_attrib(y, "var", NS_SI );
1814 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1815 xmlnode_put_attrib(y, "var", NS_SIFILE );
1817 if(conf->getourid(jhook.proto).additional["acknowledgements"] == "1") {
1818 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "feature");
1819 xmlnode_put_attrib(y, "var", NS_RECEIPTS);
1822 jab_send(jc, x);
1823 xmlnode_free(x);
1826 bool jabberhook::isourid(const string &jid) {
1827 icqconf::imaccount acc = conf->getourid(jhook.proto);
1828 int pos;
1830 string ourjid = acc.nickname;
1831 if(ourjid.find("@") == -1) ourjid += (string) "@" + acc.server;
1832 if((pos = ourjid.find(":")) != -1) ourjid.erase(pos);
1834 return jidnormalize(jid) == ourjid;
1837 string jabberhook::getourjid() {
1838 icqconf::imaccount acc = conf->getourid(jhook.proto);
1839 string jid = acc.nickname;
1840 int pos;
1842 if(jid.find("@") == -1)
1843 jid += (string) "@" + acc.server;
1845 if((pos = jid.find(":")) != -1)
1846 jid.erase(pos);
1848 if(jid.find("/") == -1)
1849 jid += "/centerim" + jhook.uuid;
1851 return jid;
1854 imstatus jabberhook::process_presence(string id, string s, char prio, imstatus ust)
1856 if (statuses.find(id) == statuses.end()) { // new and only presence
1857 if (ust != offline)
1858 (statuses[id])[s] = pair<char, imstatus>(prio, ust);
1859 } else {
1860 if (statuses[id].find(s) == statuses[id].end()) { // unknown resource
1861 if (ust != offline)
1862 (statuses[id])[s] = pair<char, imstatus>(prio, ust);
1863 } else {
1864 if (ust == offline) // remove resource
1865 (statuses[id]).erase(s);
1866 else { // known contact
1867 (statuses[id])[s] = pair<char, imstatus>(prio, ust);
1870 ust = get_presence(statuses[id]);
1872 return ust;
1875 // ----------------------------------------------------------------------------
1877 void jabberhook::statehandler(jconn conn, int state) {
1878 static int previous_state = -1;
1880 switch(state) {
1881 case JCONN_STATE_OFF:
1882 jhook.flogged = jhook.fonline = false;
1884 if(previous_state != JCONN_STATE_OFF) {
1885 logger.putourstatus(jhook.proto, jhook.getstatus(), jhook.ourstatus = offline);
1886 jhook.log(logDisconnected);
1887 jhook.roster.clear();
1888 jhook.agents.clear();
1889 jhook.ignore_ids.clear();
1890 clist.setoffline(jhook.proto);
1891 face.update();
1893 break;
1895 case JCONN_STATE_CONNECTED:
1896 break;
1898 case JCONN_STATE_AUTH:
1899 break;
1901 case JCONN_STATE_ON:
1902 if(jhook.regmode) jhook.fonline = true;
1903 break;
1905 default:
1906 break;
1909 previous_state = state;
1912 void jabberhook::packethandler(jconn conn, jpacket packet) {
1913 char *p;
1914 xmlnode x, y;
1915 string from, type, body, enc, ns, id, u, h, s, packet_id;
1916 imstatus ust;
1917 int npos;
1918 bool isagent;
1920 jpacket_reset(packet);
1922 p = xmlnode_get_attrib(packet->x, "from"); if(p) from = p;
1923 p = xmlnode_get_attrib(packet->x, "type"); if(p) type = p;
1924 p = xmlnode_get_attrib(packet->x, "id"); if (p) packet_id = p;
1926 imcontact ic(jidtodisp(from), jhook.proto);
1928 switch(packet->type) {
1929 case JPACKET_MESSAGE:
1930 x = xmlnode_get_tag(packet->x, "body");
1931 p = xmlnode_get_data(x); if(p) body = p;
1933 if(x = xmlnode_get_tag(packet->x, "subject"))
1934 if(p = xmlnode_get_data(x))
1935 body = (string) p + ": " + body;
1937 /* there can be multiple <x> tags. we're looking for one with
1938 xmlns = jabber:x:encrypted */
1940 for(x = xmlnode_get_firstchild(packet->x); x; x = xmlnode_get_nextsibling(x)) {
1941 if((p = xmlnode_get_name(x)) && !strcmp(p, "x"))
1942 if((p = xmlnode_get_attrib(x, "xmlns")) && !strcasecmp(p, "jabber:x:encrypted"))
1943 if(p = xmlnode_get_data(x)) {
1944 enc = p;
1945 break;
1949 if(!body.empty())
1950 jhook.gotmessage(type, from, body, enc);
1952 if(jhook.getstatus() != invisible) {
1953 if(x = xmlnode_get_tag(packet->x, "request"))
1954 if(NSCHECK(x, NS_RECEIPTS)) {
1955 const char *id = xmlnode_get_attrib(packet->x, "id");
1956 xmlnode receipt = jutil_receiptnew(from.c_str(), id);
1957 jab_send(conn, receipt);
1958 xmlnode_free(receipt);
1959 icqcontact *c = clist.get(ic);
1960 c->sentAcks.insert(em.getevents(ic, 1).back()->getsenttimestamp());
1961 face.relaxedupdate();
1962 if(c->isopenedforchat())
1963 c->sethasevents(true);
1967 if(x = xmlnode_get_tag(packet->x, "received"))
1969 if(p = xmlnode_get_attrib(packet->x, "id"))
1971 icqcontact *c = clist.get(ic);
1972 c->receivedAcks.insert(strtoul(p, 0, 0));
1973 face.relaxedupdate();
1974 if(c->isopenedforchat())
1975 c->sethasevents(true);
1979 break;
1981 case JPACKET_IQ:
1982 if(type == "result") {
1983 if(p = xmlnode_get_attrib(packet->x, "id")) {
1984 int iid = atoi(p);
1986 if(iid == jhook.id) {
1987 if(!jhook.regmode) {
1988 if(jhook.jstate == STATE_GETAUTH) {
1989 if(x = xmlnode_get_tag(packet->x, "query"))
1990 if(!xmlnode_get_tag(x, "digest")) {
1991 jhook.jc->sid = 0;
1994 jhook.id = atoi(jab_auth(jhook.jc));
1995 jhook.jstate = STATE_SENDAUTH;
1997 } else {
1998 jhook.gotloggedin();
1999 jhook.jstate = STATE_LOGGED;
2002 } else {
2003 jhook.regdone = true;
2006 return;
2009 if(!strcmp(p, "VCARDreq")) {
2010 x = xmlnode_get_firstchild(packet->x);
2011 if(!x) x = packet->x;
2013 jhook.gotvcard(ic, x);
2014 return;
2016 } else if(!strcmp(p, "versionreq")) {
2017 jhook.gotversion(ic, packet->x);
2018 return;
2023 if(x = xmlnode_get_tag(packet->x, "query")) {
2024 p = xmlnode_get_attrib(x, "xmlns"); if(p) ns = p;
2026 if(ns == NS_ROSTER) {
2027 jhook.gotroster(x);
2029 } else if(ns == NS_AGENTS) {
2030 for(y = xmlnode_get_tag(x, "agent"); y; y = xmlnode_get_nextsibling(y)) {
2031 const char *alias = xmlnode_get_attrib(y, "jid");
2033 if(alias) {
2034 const char *name = xmlnode_get_tag_data(y, "name");
2035 const char *desc = xmlnode_get_tag_data(y, "description");
2036 const char *service = xmlnode_get_tag_data(y, "service");
2037 agent::agent_type atype = agent::atUnknown;
2039 if(xmlnode_get_tag(y, "groupchat")) atype = agent::atGroupchat; else
2040 if(xmlnode_get_tag(y, "transport")) atype = agent::atTransport; else
2041 if(xmlnode_get_tag(y, "search")) atype = agent::atSearch;
2043 if(alias && name && desc) {
2044 jhook.agents.push_back(agent(alias, name, desc, atype));
2046 if(atype == agent::atSearch) {
2047 x = jutil_iqnew (JPACKET__GET, NS_SEARCH);
2048 xmlnode_put_attrib(x, "to", alias);
2049 xmlnode_put_attrib(x, "id", "Agent info");
2050 jab_send(conn, x);
2051 xmlnode_free(x);
2054 if(xmlnode_get_tag(y, "register")) {
2055 x = jutil_iqnew (JPACKET__GET, NS_REGISTER);
2056 xmlnode_put_attrib(x, "to", alias);
2057 xmlnode_put_attrib(x, "id", "Agent info");
2058 jab_send(conn, x);
2059 xmlnode_free(x);
2065 if(find(jhook.agents.begin(), jhook.agents.end(), DEFAULT_CONFSERV) == jhook.agents.end())
2066 jhook.agents.insert(jhook.agents.begin(), agent(DEFAULT_CONFSERV, DEFAULT_CONFSERV,
2067 _("Default Jabber conference server"), agent::atGroupchat));
2069 } else if(ns == NS_SEARCH || ns == NS_REGISTER) {
2070 p = xmlnode_get_attrib(packet->x, "id"); id = p ? p : "";
2072 if(id == "Agent info") {
2073 jhook.gotagentinfo(packet->x);
2074 } else if(id == "Lookup") {
2075 jhook.gotsearchresults(packet->x);
2076 } else if(id == "Register") {
2077 x = jutil_iqnew(JPACKET__GET, NS_REGISTER);
2078 xmlnode_put_attrib(x, "to", from.c_str());
2079 xmlnode_put_attrib(x, "id", "Agent info");
2080 jab_send(conn, x);
2081 xmlnode_free(x);
2082 } else if (ns == NS_SEARCH) {
2083 jhook.gotagentinfo(packet->x);
2085 } else if(ns == NS_DISCOITEMS) {
2086 for(y = xmlnode_get_tag(x, "item"); y; y = xmlnode_get_nextsibling(y)) {
2087 if (p = xmlnode_get_attrib(y, "jid")) {
2088 jhook.agents.push_back(agent(p, p, _(""), agent::atUnknown));
2089 x = jutil_iqnew(JPACKET__GET, NS_DISCOINFO);
2090 char *pid = jab_getid(conn);
2091 jhook.ignore_ids.insert((string)pid);
2092 xmlnode_put_attrib(x, "id", pid);
2093 xmlnode_put_attrib(x, "to", p);
2094 jab_send(conn, x);
2095 xmlnode_free(x);
2099 else if(ns == NS_DISCOINFO) {
2100 jhook.gotagentinfo(packet->x);
2104 } else if(type == "get") {
2105 if( x = xmlnode_get_tag(packet->x, "query") )
2106 if( p = xmlnode_get_attrib( x, "xmlns" ) )
2108 if(!strcmp(p, NS_VERSION)) { //user request our version
2109 jhook.full_jids[ic.nickname] = from;
2110 jhook.sendversion(ic, packet->x);
2111 return;
2114 // send the supported features (and don't leak our presence)
2115 if(!strcmp(p, NS_DISCOINFO) && jhook.getstatus() != invisible) {
2116 jhook.full_jids[ic.nickname] = from;
2117 jhook.senddiscoinfo(ic, packet->x);
2118 return;
2121 // unknown IQ get without specific response
2122 x = jutil_iqnew2(JPACKET__ERROR);
2123 xmlnode_put_attrib(x, "to", from.c_str());
2124 xmlnode_put_attrib(x, "id", packet_id.c_str());
2125 y = xmlnode_insert_tag(x, "error");
2126 xmlnode_put_attrib(y, "type", "cancel");
2127 xmlnode z = xmlnode_insert_tag(y, "feature-not-implemented");
2128 xmlnode_put_attrib(z, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
2129 jab_send(conn, x);
2130 xmlnode_free(x);
2131 } else if(type == "set") {
2132 if( x = xmlnode_get_tag(packet->x, "query") )
2134 if( p = xmlnode_get_attrib( x, "xmlns" ) )
2136 if(!strcmp(p, NS_BYTESTREAMS)) {
2137 jhook.full_jids[ic.nickname] = from;
2138 #ifdef HAVE_THREAD
2139 jhook.getfile_byte(ic, packet->x);
2140 #endif
2141 return;
2143 else if(!strcmp(p, NS_OOB)) {
2144 jhook.full_jids[ic.nickname] = from;
2145 #ifdef HAVE_THREAD
2146 jhook.getfile_http(ic, packet->x);
2147 #endif
2148 return;
2152 else if( x = xmlnode_get_tag(packet->x, "si") )
2153 if( p = xmlnode_get_attrib( x, "xmlns" ) )
2155 if(!strcmp(p, NS_SI)) {
2156 if( p = xmlnode_get_attrib( x, "profile" ) )
2158 if(!strcmp(p, NS_SIFILE)) {
2160 jhook.full_jids[ic.nickname] = from;
2161 #ifdef HAVE_THREAD
2162 jhook.file_transfer_request(ic, packet->x);
2163 #endif
2164 return;
2170 // unknown IQ set without specific response
2171 x = jutil_iqnew2(JPACKET__ERROR);
2172 xmlnode_put_attrib(x, "to", from.c_str());
2173 xmlnode_put_attrib(x, "id", packet_id.c_str());
2174 y = xmlnode_insert_tag(x, "error");
2175 xmlnode_put_attrib(y, "type", "cancel");
2176 xmlnode z = xmlnode_insert_tag(y, "feature-not-implemented");
2177 xmlnode_put_attrib(z, "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas");
2178 jab_send(conn, x);
2179 xmlnode_free(x);
2181 } else if(type == "error") {
2182 string name, desc;
2183 int code;
2185 x = xmlnode_get_tag(packet->x, "error");
2186 p = xmlnode_get_attrib(x, "code"); if(p) code = atoi(p);
2187 p = xmlnode_get_attrib(x, "id"); if(p) name = p;
2188 p = xmlnode_get_tag_data(packet->x, "error"); if(p) desc = p;
2190 set<string>::iterator sit;
2191 if ((sit = jhook.ignore_ids.find(packet_id)) != jhook.ignore_ids.end()) { // expected error, ignore
2192 jhook.ignore_ids.erase(sit);
2193 break;
2196 switch(code) {
2197 case 501: /* Not Implemented */
2198 if(jhook.regmode) {
2199 jhook.regerr = desc;
2201 break;
2202 case 401: /* Unauthorized */
2203 case 302: /* Redirect */
2204 case 400: /* Bad request */
2205 case 402: /* Payment Required */
2206 case 403: /* Forbidden */
2207 case 404: /* Not Found */
2208 case 405: /* Not Allowed */
2209 case 406: /* Not Acceptable */
2210 case 407: /* Registration Required */
2211 case 408: /* Request Timeout */
2212 case 409: /* Conflict */
2213 case 500: /* Internal Server Error */
2214 case 502: /* Remote Server Error */
2215 case 503: /* Service Unavailable */
2216 case 504: /* Remote Server Timeout */
2217 default:
2218 if(!jhook.regmode) {
2219 face.log(desc.empty() ?
2220 _("+ [jab] error %d") :
2221 _("+ [jab] error %d: %s"),
2222 code, desc.c_str());
2224 if(!jhook.flogged) {
2225 close(jhook.jc->fd);
2226 jhook.jc->fd = -1;
2229 } else {
2230 jhook.regerr = desc;
2236 break;
2238 case JPACKET_PRESENCE:
2239 if (type == "error")
2241 if(!jhook.regmode) {
2242 string desc;
2243 int code;
2244 x = xmlnode_get_tag(packet->x, "error");
2245 p = xmlnode_get_attrib(x, "code"); if(p) code = atoi(p);
2246 p = xmlnode_get_tag_data(packet->x, "error"); if(p) desc = p;
2247 face.log(desc.empty() ?
2248 _("+ [jab] error %d") :
2249 _("+ [jab] error %d: %s"),
2250 code, desc.c_str());
2252 break;
2254 x = xmlnode_get_tag(packet->x, "show");
2255 ust = available;
2257 if(x) {
2258 p = xmlnode_get_data(x); if(p) ns = p;
2260 if(!ns.empty()) {
2261 if(ns == "away") ust = away; else
2262 if(ns == "dnd") ust = dontdisturb; else
2263 if(ns == "xa") ust = notavail; else
2264 if(ns == "chat") ust = freeforchat;
2268 if(type == "unavailable")
2269 ust = offline;
2271 jidsplit(from, u, h, s);
2272 id = jidtodisp(from);
2273 jhook.full_jids[ic.nickname] = from; //writing full JID
2275 if(clist.get(imcontact((string) "#" + id, jhook.proto))) {
2276 if(ust == offline) {
2277 vector<string>::iterator im = find(jhook.chatmembers[id].begin(), jhook.chatmembers[id].end(), s);
2278 if(im != jhook.chatmembers[id].end())
2279 jhook.chatmembers[id].erase(im);
2281 jhook.full_jids.erase(ic.nickname); //erase full JID if user change status to offline
2283 vector<agent>::iterator ia = find(jhook.agents.begin(), jhook.agents.end(), from);
2284 if(ia != jhook.agents.end())
2285 jhook.agents.erase(ia);
2286 } else {
2287 vector<string>::iterator im = find(jhook.chatmembers[id].begin(), jhook.chatmembers[id].end(), s);
2288 if(im == jhook.chatmembers[id].end()) {
2289 jhook.chatmembers[id].push_back(s);
2290 sort(jhook.chatmembers[id].begin(),jhook.chatmembers[id].end());
2294 } else {
2295 icqcontact *c = clist.get(ic);
2297 if(c) {
2298 char prio = (char) jutil_priority(packet->x); // priority
2299 ust = jhook.process_presence(id, s, prio, ust);
2300 if(c->getstatus() != ust) {
2301 jhook.awaymsgs[ic.nickname] = "";
2302 logger.putonline(c, c->getstatus(), ust);
2303 if(c->getstatus() == offline)
2305 x = jutil_iqnew(JPACKET__GET, NS_DISCOINFO);
2306 xmlnode_put_attrib(x, "id", jab_getid(conn));
2307 xmlnode_put_attrib(x, "to", from.c_str());
2308 jab_send(conn, x);
2309 xmlnode_free(x);
2310 jhook.agents.push_back(agent(from, "", "", agent::atUnknown));
2312 c->setstatus(ust);
2315 if(x = xmlnode_get_tag(packet->x, "status"))
2316 if(p = xmlnode_get_data(x))
2317 jhook.awaymsgs[ic.nickname] = p;
2320 /*This code checking if user in your contacl list send update avatar request(presence message with another hash)*/
2321 xmlnode y;
2322 if(x = xmlnode_get_tag(packet->x, "x"))
2323 if(p = xmlnode_get_attrib(x, "xmlns"))
2324 if(!strcmp(p, NS_VCARDUP))
2325 if( y = xmlnode_get_tag(x, "photo")) //quering avatar hash
2326 if(p = xmlnode_get_data(y))
2328 icqcontact::basicinfo bi = c->getbasicinfo();
2329 string temp_av = bi.avatar;
2330 if( justpathname( temp_av ).empty() )
2331 temp_av = c->getdirname() + bi.avatar;
2332 string contact_dir = temp_av;
2333 if( !contact_dir.empty() )
2335 int ava_file = open( contact_dir.c_str(), O_RDONLY );
2336 if( ava_file >= 0 )
2338 struct stat buf;
2339 fstat( ava_file, &buf );
2340 long int file_size = buf.st_size;
2341 char *hash = (char*)calloc( 1, file_size+1 );
2342 read( ava_file, hash, file_size );
2343 close( ava_file );
2344 unsigned char hashval[20];
2345 char *pos;
2346 char final[41];
2347 shaBlock((unsigned char *)hash, file_size, hashval);
2348 pos = final;
2349 int k;
2350 for(k=0;k<20;k++)
2352 snprintf(pos, 3, "%02x", hashval[k]);
2353 pos += 2;
2355 if( strcmp( p, final ) != 0 )
2356 jhook.requestinfo(c);
2357 free(hash);
2359 else
2360 jhook.requestinfo(c);
2365 #ifdef HAVE_GPGME
2366 if(x = xmlnode_get_tag(packet->x, "x"))
2367 if(p = xmlnode_get_attrib(x, "xmlns"))
2368 if((string) p == "jabber:x:signed")
2369 if(p = xmlnode_get_data(x))
2370 c->setpgpkey(pgp.verify(p, jhook.awaymsgs[ic.nickname]));
2371 #endif
2374 break;
2376 case JPACKET_S10N:
2377 isagent = find(jhook.agents.begin(), jhook.agents.end(), from) != jhook.agents.end();
2379 if(type == "subscribe") {
2380 if(!isagent) {
2381 em.store(imauthorization(ic, imevent::incoming,
2382 imauthorization::Request, _("The user wants to subscribe to your network presence updates")));
2384 } else {
2385 char *cfrom = strdup(from.c_str());
2386 x = jutil_presnew(JPACKET__SUBSCRIBED, cfrom, 0);
2387 jab_send(jhook.jc, x);
2388 xmlnode_free(x);
2389 free (cfrom);
2392 } else if(type == "unsubscribe") {
2393 char *cfrom = strdup(from.c_str());
2394 x = jutil_presnew(JPACKET__UNSUBSCRIBED, cfrom, 0);
2395 jab_send(jhook.jc, x);
2396 xmlnode_free(x);
2397 em.store(imnotification(ic, _("The user has removed you from his contact list (unsubscribed you, using the Jabber language)")));
2398 free (cfrom);
2402 break;
2404 default:
2405 break;
2408 set<string>::iterator idit;
2409 if ((idit = jhook.ignore_ids.find(packet_id)) != jhook.ignore_ids.end()) { // erase ignores for packets we've received
2410 jhook.ignore_ids.erase(idit);
2414 void jabberhook::jlogger(jconn conn, int inout, const char *p) {
2415 string tolog = (string) (inout ? "[IN]" : "[OUT]") + "\n";
2416 tolog += p;
2417 face.log(tolog);
2420 bool jabberhook::get_img_ext(const string &type, string &ext) {
2421 int pos;
2423 if(type.find("image/") != -1) {
2424 if((pos = type.find("/")) != -1) {
2425 ext = type.substr(pos+1);
2426 return true;
2429 ext = (string)"";
2430 return false;
2434 bool jabberhook::get_base64_avatar(string &type, string &ava) {
2436 icqcontact *ic = clist.get(contactroot);
2437 icqcontact::basicinfo bi = ic->getbasicinfo();
2438 string contact_dir = conf->getdirname();
2440 if(!bi.avatar.empty())
2442 if( justpathname( bi.avatar ).empty() )
2443 contact_dir += bi.avatar;
2444 else
2445 contact_dir = bi.avatar;
2446 string image_type = contact_dir;
2447 int pos;
2448 if( (pos = image_type.rfind( ".")) != -1 )
2450 type += (string)"image/" + image_type.substr(pos+1);
2451 int avatar_file = open( contact_dir.c_str(), O_RDONLY );
2452 if( avatar_file >= 0 )
2454 struct stat buf;
2455 fstat( avatar_file, &buf );
2456 long int file_size = buf.st_size;
2457 char *avatar_stream = (char*)calloc( 1, file_size+1 );
2458 read( avatar_file, avatar_stream, file_size );
2459 close( avatar_file );
2460 char *temp = base64_encode(avatar_stream, file_size);
2461 ava = temp;
2462 free(temp);
2463 free(avatar_stream);
2464 return true;
2469 return false;
2472 bool jabberhook::get_my_avatar_hash(string &my_hash)
2474 icqcontact *ic = clist.get(contactroot);
2475 icqcontact::basicinfo bi = ic->getbasicinfo();
2476 string contact_dir = conf->getdirname();
2478 if(!bi.avatar.empty())
2480 if( justpathname( bi.avatar ).empty() )
2481 contact_dir += bi.avatar;
2482 else
2483 contact_dir = bi.avatar;
2484 int ava_file = open( contact_dir.c_str(), O_RDONLY );
2486 if( ava_file >= 0 )
2488 struct stat buf;
2489 fstat( ava_file, &buf );
2490 long int file_size = buf.st_size;
2491 char *hash = (char*)calloc( 1, file_size+1 );
2492 read( ava_file, hash, file_size );
2493 close( ava_file );
2494 unsigned char hashval[20];
2495 char *pos;
2496 char final[41];
2497 shaBlock((unsigned char *)hash, file_size, hashval);
2498 pos = final;
2499 int k;
2500 for(k=0;k<20;k++)
2502 snprintf(pos, 3, "%02x", hashval[k]);
2503 pos += 2;
2505 my_hash = final;
2506 free(hash);
2507 return true;
2510 return false;
2513 bool jabberhook::url_port_get(const string &full_url, string &url, int &port, string &tail, string &filename) {
2515 int pos;
2517 url = full_url;
2518 string temp;
2519 if( (pos = url.find(":")) != -1) {
2520 if((pos = url.find(":", pos+1)) != -1) {
2521 temp = url.substr(pos+1);
2522 if((pos = temp.find("/")) != -1) {
2523 tail = temp.substr(pos);
2524 temp.erase(pos);
2525 port = atoi(temp.c_str());
2526 if((pos = tail.rfind("/")) != -1) {
2527 filename = tail.substr(pos+1);
2528 url = url.substr(7); //remove http://
2529 if((pos = url.find(":")) != -1) {
2530 url.erase(pos); //remove after :port/
2531 return true;
2538 return false;
2542 void jabberhook::send_file(const string &cjid) //http sendfile
2544 int ptpmin, ptpmax;
2545 vector<imfile::record> files = srfiles[cjid].first.getfiles();
2546 int ir = srfiles[cjid].second.second;
2547 string full_jid = jhook.full_jids[cjid];
2549 if( ir < files.size() )
2551 struct send_file *file = (struct send_file *)srfiles[cjid].second.first;
2553 xmlnode x, y;
2555 x = jutil_iqnew(JPACKET__SET, NS_OOB);
2556 xmlnode_put_attrib(x, "from", getourjid().c_str());
2557 xmlnode_put_attrib(x, "to", full_jid.c_str());
2559 string new_id = (string)"centerim" + i2str(rand());
2561 xmlnode_put_attrib(x, "id", new_id.c_str());
2562 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "url");
2564 conf->getpeertopeer(ptpmin, ptpmax); //getting max and min port range
2566 jabber_send_file(jhook.jc, files[ir].fname.c_str(), files[ir].size, file, strdup(cjid.c_str()), &progressbar, ptpmin, ptpmax ); //real send fuction, starting server
2567 string send_url = (string)"http://" + file->host + (string)":" + i2str(file->port) + (string)"/" + justfname(files[ir].fname);
2568 xmlnode_insert_cdata(y, send_url.c_str(), (unsigned) -1 );
2570 xmlnode k;
2571 k = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "desc");
2572 string desc = "File size: " + i2str(files[ir].size);
2573 xmlnode_insert_cdata(k, desc.c_str(), (unsigned) -1 );
2575 if(x) {
2576 jab_send(jc, x);
2577 xmlnode_free(x);
2582 bool jabberhook::knowntransfer(const imfile &fr) const {
2583 return transferinfo.find(fr) != transferinfo.end();
2586 void jabberhook::replytransfer(const imfile &fr, bool accept, const string &localpath) {
2587 struct send_file *file = (struct send_file *)transferinfo[fr].first;
2588 if(accept) {
2589 transferinfo[fr].second = localpath;
2590 if(transferinfo[fr].second.substr(transferinfo[fr].second.size()-1) != "/")
2591 transferinfo[fr].second += "/";
2593 transferinfo[fr].second += justfname(fr.getfiles().begin()->fname);
2594 if(file)
2596 if(file->transfer_type == 0) //socks5 file transfer
2597 jhook.bytenegotiat(fr);
2598 if(file->transfer_type == 1) //http file transfer
2599 getfile(fr);
2603 } else { clean_up_file(fr, 0);
2608 void jabberhook::aborttransfer(const imfile &fr) {//overloaded function to aborting filetransfers
2610 if( fr.getdirection() == imevent::incoming )
2612 if( transferinfo.find(fr) != transferinfo.end() )
2614 face.transferupdate(fr.getfiles().begin()->fname, fr,icqface::tsCancel, 0, 0);
2615 clean_up_file(fr, 0); //do some cleanups
2618 else
2620 string sr = back_srfiles[fr];
2621 if( back_srfiles.find(fr) != back_srfiles.end() )
2623 vector<imfile::record> files = fr.getfiles();
2624 face.transferupdate(files[srfiles[sr].second.second].fname, fr,icqface::tsCancel, 0, 0);
2625 clean_up_file(fr, 1, (char*)sr.c_str()); //do some cleanups
2630 void jabberhook::progressbar(void *file, long int bytes, long int size, int status, int conn_type ) { //conn_type - litle trick to easy determine send or recieve conn. type
2631 char *jid = (char*)file;
2632 if( conn_type == 0 )
2634 if( jhook.transferusers.find(jid) != jhook.transferusers.end() )
2636 imfile fr = jhook.transferusers[jid];
2637 switch(status)
2639 case 0:
2640 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsProgress, size, bytes);
2641 break;
2642 case 1:
2643 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsFinish, size, 0);
2644 jhook.clean_up_file(fr, 0);
2645 break;
2646 default:
2647 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsError, 0, 0);
2648 jhook.clean_up_file(fr, 0);
2649 break;
2653 else if( conn_type == 1 )
2655 if( jhook.srfiles.find(jid) != jhook.srfiles.end() )
2657 imfile fr = jhook.srfiles[jid].first;
2658 vector<imfile::record> files = fr.getfiles();
2659 int ir = jhook.srfiles[jid].second.second;
2661 if( files.size() > ir )
2663 switch(status)
2665 case 0:
2666 face.transferupdate(files[ir].fname, fr, icqface::tsProgress, size, bytes);
2667 break;
2668 case 1:
2669 face.transferupdate(files[ir].fname, fr, icqface::tsFinish, size, 0);
2670 // ir++;
2671 jhook.srfiles[jid].second.second++;
2672 if( files.size() > ir )
2673 jhook.send_file(jid);
2674 else
2675 jhook.clean_up_file(fr, 1, jid);
2676 break;
2677 default:
2678 face.transferupdate(files[ir].fname, fr, icqface::tsError, 0, 0);
2679 jhook.clean_up_file(fr, 1, jid);
2680 break;
2687 void jabberhook::file_transfer_request(const imcontact &ic, xmlnode i) { //stream initialization request xep-0066
2688 char *p;
2689 char *filename, *filesize, *id;
2690 xmlnode x, z;
2692 p = xmlnode_get_attrib(i, "id");
2693 if(p)
2694 id = p;
2695 else
2696 return;
2698 x = xmlnode_get_tag(i, "si");
2699 z = xmlnode_get_tag(x, "file");
2701 p = xmlnode_get_attrib(z, "name");
2702 if(p)
2703 filename = p;
2704 else
2705 return;
2707 p = xmlnode_get_attrib(z, "size");
2708 if(p)
2709 filesize = p;
2710 else
2711 return;
2714 struct send_file *trans_file = (struct send_file *)malloc( sizeof( struct send_file ) );
2715 trans_file->full_jid_name = strdup( jhook.full_jids[jidnormalize(ic.nickname).c_str()].c_str() );
2716 trans_file->id = strdup(id);
2718 trans_file->host = NULL;
2719 trans_file->url = NULL;
2720 trans_file->sid_from_to = NULL;
2722 trans_file->transfer_type = 0;
2724 imfile::record r;
2725 //get filename and filesize from request
2726 r.fname = filename;
2727 r.size = atoi(filesize);
2729 imfile fr(ic, imevent::incoming, "", vector<imfile::record>(1, r));
2730 jhook.transferinfo[fr].first = trans_file;
2732 transferusers[jidnormalize(ic.nickname)] = fr; //little hack
2734 em.store(fr);
2735 face.transferupdate(r.fname, fr, icqface::tsInit, r.size, 0);
2739 void jabberhook::bytenegotiat(const imfile &fr) { //stream initialization result (xep-0066) for socks 5 bytestreams
2740 if( transferinfo.find(fr) != transferinfo.end() )
2742 struct send_file *file = (struct send_file *)transferinfo[fr].first;
2743 char *cjid = file->full_jid_name;
2744 char *id = file->id;
2746 xmlnode x0, x, q, w, e, y, z;
2748 x0 = jutil_iqnew2(JPACKET__RESULT);
2749 xmlnode_put_attrib(x0, "to", cjid);
2750 xmlnode_put_attrib(x0, "from", getourjid().c_str());
2751 xmlnode_put_attrib(x0, "id", id );
2753 y = xmlnode_insert_tag(x0, "si");
2754 xmlnode_put_attrib(y, "xmlns", NS_SI);
2756 z = xmlnode_insert_tag(xmlnode_get_tag(x0,"si"), "feature");
2757 xmlnode_put_attrib(z, "xmlns", NS_NEG);
2759 x = xmlnode_insert_tag(z, "x");
2760 xmlnode_put_attrib(x, "xmlns", NS_DATA);
2761 xmlnode_put_attrib(x, "type", "submit");
2763 q = xmlnode_insert_tag(x, "field");
2764 xmlnode_put_attrib(q, "var", "stream-method");
2766 w = xmlnode_insert_tag(q, "value");
2767 xmlnode_insert_cdata(w, NS_BYTESTREAMS, (unsigned) -1 );
2769 jab_send(jc, x0);
2770 xmlnode_free(x0);
2774 void jabberhook::reject_file(const imfile &fr) { //don't want to recieve file . xep-0065(socks5 bytestream)
2775 if( transferinfo.find(fr) != transferinfo.end() )
2777 struct send_file *file = (struct send_file *)transferinfo[fr].first;
2779 xmlnode x0 = jutil_iqnew2(JPACKET__RESULT), y,z;
2780 xmlnode_put_attrib(x0, "to", file->full_jid_name);
2781 xmlnode_put_attrib(x0, "from", getourjid().c_str());
2782 xmlnode_put_attrib(x0, "id", file->id);
2784 jab_send(jc, x0);
2785 xmlnode_free(x0);
2790 void jabberhook::getfile_result(const imfile &fr) { //socks5 bytestream activation request xep-0065
2791 //prepare acknowledge packageto reciever
2792 if( transferinfo.find(fr) != transferinfo.end() )
2794 struct send_file *file = (struct send_file *)transferinfo[fr].first;
2795 if(file)
2797 if( file->full_jid_name && file->id )
2799 xmlnode x = jutil_iqnew(JPACKET__RESULT, NS_BYTESTREAMS), y;
2800 xmlnode_put_attrib(x, "to", file->full_jid_name);
2801 xmlnode_put_attrib(x, "from", getourjid().c_str());
2802 xmlnode_put_attrib(x, "id", file->id );
2803 y = xmlnode_insert_tag(xmlnode_get_tag(x,"query"), "streamhost-used");
2804 xmlnode_put_attrib(y, "jid", file->full_jid_name );
2805 jab_send(jc, x);
2806 xmlnode_free(x);
2812 void jabberhook::getfile_http(const imcontact &ic, xmlnode i) { //xep-0066
2814 string full_url, host, url, filename;
2815 int port;
2816 char *p;
2817 char *id;
2819 xmlnode x, y;
2821 p = xmlnode_get_attrib(i, "id");
2822 if(p)
2823 id = p;
2824 else
2825 return;
2827 x = xmlnode_get_tag(i, "query");
2828 y = xmlnode_get_tag(x, "url");
2829 p = xmlnode_get_data(y);
2830 if(p)
2831 full_url = p;
2832 else
2833 return;
2836 struct send_file *trans_file = (struct send_file *)malloc( sizeof( struct send_file ) );
2837 trans_file->full_jid_name = strdup( jhook.full_jids[jidnormalize(ic.nickname).c_str()].c_str() );
2838 trans_file->id = strdup(id);
2839 if( url_port_get(full_url, host, port, url, filename) )
2841 trans_file->host = strdup(host.c_str());
2842 trans_file->url = strdup(url.c_str());
2843 trans_file->port = port;
2844 trans_file->sid_from_to = NULL;
2845 trans_file->transfer_type = 1;
2848 imfile::record r;
2849 r.fname = filename;
2850 r.size = -1; //http initialization request over xmpp we don't know filesize :(
2852 imfile fr(ic, imevent::incoming, "", vector<imfile::record>(1, r));
2853 jhook.transferinfo[fr].first = trans_file;
2855 transferusers[jidnormalize(ic.nickname)] = fr; //little hack to create association imfile with JID
2857 em.store(fr);
2858 face.transferupdate(r.fname, fr, icqface::tsInit, r.size, 0);
2863 void jabberhook::getfile(const imfile &fr) {
2864 if( transferinfo.find(fr) != transferinfo.end() )
2866 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsStart, 0, 0);
2868 struct send_file *file = (struct send_file *)transferinfo[fr].first;
2869 if(file)
2871 if( file->transfer_type == 0 )//bytestream method
2873 #ifdef HAVE_THREAD
2874 jabber_get_file(jhook.jc, transferinfo[fr].second.c_str(), fr.getfiles().begin()->size, file, strdup( jidtodisp(file->full_jid_name).c_str() ), &progressbar);
2875 jhook.getfile_result(fr);
2876 #endif
2878 else if( file->transfer_type == 1 )//http GET method
2880 #ifdef HAVE_THREAD
2881 jabber_get_file(jhook.jc, transferinfo[fr].second.c_str(), fr.getfiles().begin()->size, file, strdup( jidtodisp(file->full_jid_name).c_str() ), &progressbar);
2882 #endif
2888 //parse bytestream xmpp request
2889 void jabberhook::getfile_byte(const imcontact &ic, xmlnode i) {
2891 char *host, *jid, *sid;
2892 int port;
2893 char *p;
2895 xmlnode x, z;
2897 x = xmlnode_get_tag(i, "query"), z;
2898 p = xmlnode_get_attrib(x, "sid");
2899 if(p)
2900 sid = p;
2901 else
2902 return;
2904 z = xmlnode_get_tag(x, "streamhost");
2905 p = xmlnode_get_attrib(z, "host");
2906 if(p)
2907 host = p;
2908 else
2909 return;
2911 p = xmlnode_get_attrib(z, "jid");
2912 if(p)
2913 jid = p;
2914 else
2915 return;
2917 p = xmlnode_get_attrib(z, "port");
2918 if(p)
2919 port = atoi(p);
2920 else
2921 return;
2923 string sid_from_to = (string)sid + (string)jid + getourjid() ;
2924 imfile fr = transferusers[jidnormalize(ic.nickname)];
2925 if( transferinfo.find(fr) != transferinfo.end() )
2927 struct send_file *file = (struct send_file *)transferinfo[fr].first;
2928 file->sid_from_to = strdup( sid_from_to.c_str() );
2929 file->port = port;
2930 file->host = strdup( host );
2931 file->url = NULL;
2932 getfile(fr);
2936 void jabberhook::clean_up_file(const imfile &fr, int trans_type, char *cjid )
2939 struct send_file *file;
2940 if(trans_type == 0)
2942 if(transferinfo.find(fr) != transferinfo.end())
2943 file = (struct send_file *)transferinfo[fr].first;
2944 else
2945 return;
2947 else if(trans_type == 1)
2949 if(!cjid)
2950 return;
2951 if(srfiles.find(cjid) != srfiles.end())
2952 file = (struct send_file *)srfiles[cjid].second.first;
2953 else
2954 return;
2956 else
2957 return;
2959 if(file)
2961 #ifdef HAVE_THREAD
2962 pthread_cancel(file->thread);
2963 #endif
2964 if(file->full_jid_name)
2966 if(trans_type == 0)
2967 transferusers.erase(jidtodisp(file->full_jid_name));
2968 else if(trans_type == 1)
2969 back_srfiles.erase(srfiles[cjid].first);
2970 free(file->full_jid_name);
2972 if(file->id)
2973 free(file->id);
2974 if(file->host)
2975 free(file->host);
2976 if(file->url)
2977 free(file->url);
2978 if(file->sid_from_to)
2979 free(file->sid_from_to);
2980 free(file);
2981 if(trans_type == 0)
2982 transferinfo[fr].first = NULL;
2983 else if (trans_type == 1)
2984 srfiles[cjid].second.first = NULL;
2986 if(trans_type == 0)
2987 transferinfo.erase(fr);
2988 if(trans_type == 1)
2989 srfiles.erase(cjid);
2994 #endif