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
25 #include "icqcommon.h"
29 #include "jabberhook.h"
32 #include "eventmanager.h"
33 #include "icqgroups.h"
35 #include "icqcontacts.h"
49 #define DEFAULT_CONFSERV "conference.jabber.org"
50 #define PERIOD_KEEPALIVE 30
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 )
62 char* res
= (char*)malloc(((( bufferLen
+2 )*4 )/3 ) + 1);
66 unsigned char igroup
[3];
69 char *peob
= buffer
+ bufferLen
;
71 for ( p
= buffer
; p
< peob
; ) {
72 igroup
[ 0 ] = igroup
[ 1 ] = igroup
[ 2 ] = 0;
74 for ( n
=0; n
<3; n
++ ) {
75 if ( p
>= peob
) break;
76 igroup
[n
] = ( unsigned char ) *p
;
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 ];
99 static char *base64_decode(const char *str
, int *ret_len
)
113 if (*c
>= 'A' && *c
<= 'Z') {
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
== '+') {
121 } else if (*c
== '/') {
123 } else if (*c
== '\r' || *c
== '\n') {
126 } else if (*c
== '=') {
128 out
= (char*)realloc(out
, len
+ 2);
129 out
[len
] = (char)(tmp2
>> 10) & 0xff;
131 out
[len
] = (char)(tmp2
>> 2) & 0xff;
134 out
= (char*)realloc(out
, len
+ 1);
135 out
[len
] = (char)(tmp2
>> 4) & 0xff;
140 tmp2
= ((tmp2
<< 6) | (tmp
& 0xff));
143 out
= (char*)realloc(out
, len
+ 3);
144 out
[len
] = (char)((tmp2
>> 16) & 0xff);
146 out
[len
] = (char)((tmp2
>> 8) & 0xff);
148 out
[len
] = (char)(tmp2
& 0xff);
156 out
= (char*)realloc(out
, len
+ 1);
165 static void jidsplit(const string
&jid
, string
&user
, string
&host
, string
&rest
) {
169 if((pos
= user
.find("/")) != -1) {
170 rest
= user
.substr(pos
+1);
174 if((pos
= user
.find("@")) != -1) {
175 host
= user
.substr(pos
+1);
184 static string
jidtodisp(const string
&jid
) {
185 string user
, host
, rest
;
186 jidsplit(jid
, user
, host
, rest
);
189 user
+= (string
) "@" + host
;
196 static imstatus
get_presence(std::map
<string
, pair
<char, imstatus
> > res
) // <resource, <prio, status> >
200 imstatus result
= offline
;
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
;
214 // ----------------------------------------------------------------------------
218 string
jabberhook::jidnormalize(const string
&jid
) const {
219 if(find(agents
.begin(), agents
.end(), jid
) != agents
.end())
222 string user
, host
, rest
;
223 jidsplit(jid
, user
, host
, rest
);
226 host
= conf
->getourid(proto
).server
;
231 user
+= (string
) "@" + host
;
232 if(!rest
.empty()) user
+= (string
) "/" + rest
;
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
);
253 fcapabs
.insert(hookcapab::files
);
255 fcapabs
.insert(hookcapab::pgp
);
256 fcapabs
.insert(hookcapab::acknowledgements
);
259 jabberhook::~jabberhook() {
262 void jabberhook::init() {
264 snprintf(rnd
, 9, "%X%X", rand()%0xFFFF, rand()%0xFFFF);
266 manualstatus
= conf
->getstatus(proto
);
269 void jabberhook::connect() {
270 icqconf::imaccount acc
= conf
->getourid(proto
);
271 string jid
= getourjid();
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;
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
);
297 jab_logger(jc
, &jlogger
);
301 jstate
= STATE_CONNECTING
;
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
324 void jabberhook::exectimers() {
326 if(timer_current
-timer_keepalive
> PERIOD_KEEPALIVE
) {
327 jab_send_raw(jc
, " \t ");
328 timer_keepalive
= timer_current
;
333 void jabberhook::main() {
337 if(jc
&& jc
->state
== JCONN_STATE_CONNECTING
) {
344 if(jstate
== STATE_CONNECTING
) {
346 x
= jutil_iqnew(JPACKET__GET
, NS_AUTH
);
348 xmlnode_put_attrib(x
, "id", cid
);
351 z
= xmlnode_insert_tag(xmlnode_get_tag(x
, "query"), "username");
352 xmlnode_insert_cdata(z
, jc
->user
->user
, (unsigned) -1);
356 jstate
= STATE_GETAUTH
;
359 if(!jc
|| jc
->state
== JCONN_STATE_OFF
) {
360 face
.log(_("+ [jab] unable to connect to the server"));
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 {
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
);
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
);
391 bool jabberhook::online() const {
395 bool jabberhook::logged() const {
396 return fonline
&& flogged
;
399 bool jabberhook::isconnecting() const {
400 return fonline
&& !flogged
;
403 bool jabberhook::enabled() const {
407 bool jabberhook::send(const imevent
&ev
) {
408 icqcontact
*c
= clist
.get(ev
.getcontact());
409 string text
, cname
, enc
;
412 if(ev
.gettype() == imevent::message
) {
413 const immessage
*m
= static_cast<const immessage
*>(&ev
);
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);
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());
453 switch(m
->getauthtype()) {
454 case imauthorization::Granted
:
455 x
= jutil_presnew(JPACKET__SUBSCRIBED
, cjid
, 0);
457 case imauthorization::Rejected
:
458 x
= jutil_presnew(JPACKET__UNSUBSCRIBED
, cjid
, 0);
460 case imauthorization::Request
:
461 x
= jutil_presnew(JPACKET__SUBSCRIBE
, cjid
, 0);
475 text
= rusconv("ku", text
);
478 if(pgp
.enabled(ev
.getcontact())) {
479 enc
= pgp
.encrypt(text
, c
->getpgpkey(), proto
);
480 if (enc
.empty() && !text
.empty()) // probably encryption error
482 text
= "This message is encrypted.";
487 if (!otr
.send_message(proto
, jidnormalize(ev
.getcontact().nickname
), text
))
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
);
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());
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
);
520 stringstream idstream
;
521 idstream
<< ev
.gettimestamp();
522 xmlnode_put_attrib(x
, "id", idstream
.str().c_str());
525 idstream
<< ev
.gettimestamp();
526 xmlnode_put_attrib(x
, "id", idstream
.str());
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
) {
558 char *cjid
= strdup(jidnormalize(ic
.nickname
).c_str());
559 if(roster
.find(cjid
) != roster
.end()) {
564 if(report
) log(logContactAdd
, ic
.nickname
.c_str());
566 x
= jutil_presnew(JPACKET__SUBSCRIBE
, cjid
, 0);
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
);
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();
590 if(c
= clist
.get(ic
)) {
591 imcontact
icc(jidtodisp(ic
.nickname
), proto
);
592 if(ic
.nickname
!= icc
.nickname
) {
599 jidsplit(icc
.nickname
, u
, h
, r
);
603 c
->setdispnick(icc
.nickname
);
610 if(c
= clist
.get(ic
)) {
611 cname
= ic
.nickname
.substr(1);
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);
632 void jabberhook::removeuser(const imcontact
&ic
, bool report
) {
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");
661 if(report
) log(logContactRemove
, ic
.nickname
.c_str());
663 x
= jutil_presnew(JPACKET__UNSUBSCRIBE
, cjid
, 0);
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");
679 if(c
= clist
.get(ic
)) {
680 cname
= ic
.nickname
.substr(1);
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");
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
) {
701 if(getstatus() == offline
) {
711 msg
= conf
->getextstatus(proto
, st
); //external online status
712 if( msg
.empty() ) msg
= conf
->getawaymsg(proto
);
715 msg
= conf
->getawaymsg(proto
);
719 msg
= conf
->getextstatus(proto
, st
); //external online status
722 setjabberstatus(ourstatus
= st
, msg
);
725 if(getstatus() != offline
) {
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
));
738 c
->setdispnick(ia
->name
);
739 c
->setabout(ia
->desc
);
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
);
757 void jabberhook::requestawaymsg(const imcontact
&ic
) {
758 icqcontact
*c
= clist
.get(ic
);
761 string am
= awaymsgs
[ic
.nickname
];
764 em
.store(imnotification(ic
, (string
) _("Away message:") + "\n\n" + rusconv("uk",am
)));
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
) {
779 string jid
= nick
+ "@" + serv
;
781 if((pos
= jid
.find(":")) != -1) {
782 port
= atoi(jid
.substr(pos
+1).c_str());
785 port
= icqconf::defservers
[proto
].port
;
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);
802 err
= _("Wrong nickname given, cannot register");
807 jab_packet_handler(jc
, &packethandler
);
808 jab_state_handler(jc
, &statehandler
);
811 jab_logger(jc
, &jlogger
);
813 jc
->cw_state
= CW_CONNECT_BLOCKING
;
816 if(jc
) id
= atoi(jab_reg(jc
));
819 err
= _("Unable to connect");
825 while(online() && !regdone
&& regerr
.empty()) {
830 err
= regdone
? "" : regerr
;
836 void jabberhook::setjabberstatus(imstatus st
, string msg
) {
837 xmlnode x
= jutil_presnew(JPACKET__UNKNOWN
, 0, 0);
841 xmlnode_insert_cdata(xmlnode_insert_tag(x
, "show"), "away", (unsigned) -1);
846 xmlnode_insert_cdata(xmlnode_insert_tag(x
, "show"), "dnd", (unsigned) -1);
850 xmlnode_insert_cdata(xmlnode_insert_tag(x
, "show"), "chat", (unsigned) -1);
855 xmlnode_insert_cdata(xmlnode_insert_tag(x
, "show"), "xa", (unsigned) -1);
859 xmlnode_put_attrib(x
, "type", "invisible");
863 xmlnode_put_attrib(x
, "type", "unavailable");
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);
875 msg
= imstatus2str(st
);
877 while( (pos
= msg
.find( '\r' )) != string::npos
) {
878 if( msg
[pos
+1] == '\n' ) {
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);
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);
920 logger
.putourstatus(proto
, getstatus(), ourstatus
= st
);
923 void jabberhook::sendvisibility() {
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");
948 vector
<string
> jabberhook::getservices(servicetype::enumeration st
) const {
949 vector
<agent
>::const_iterator ia
= agents
.begin();
952 agent::param_type pt
;
955 case servicetype::search
:
956 pt
= agent::ptSearch
;
958 case servicetype::registration
:
959 pt
= agent::ptRegister
;
961 case servicetype::groupchat
:
962 while(ia
!= agents
.end()) {
963 if(ia
->type
== agent::atGroupchat
) r
.push_back(ia
->jid
);
970 while(ia
!= agents
.end()) {
971 if(ia
->params
[pt
].enabled
)
972 r
.push_back(ia
->name
);
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
;
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
) {
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
;
1010 while(ia
!= jhook
.agents
.end()) {
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"))
1020 if (q
= (xmlnode_get_attrib(y
, "category"))) {
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
);
1039 } else if ((q
= xmlnode_get_attrib(y
, "var")) && (!strcmp(q
, NS_RECEIPTS
))) {
1040 ia
->params
[agent::ptReceipts
].enabled
= true;
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
1051 if (name
== "instructions") {
1052 ia
->params
[agent::ptSearch
].instruction
= data
;
1053 } else if ((name
== "x") && (NSCHECK(y
, "jabber:x:data"))) {
1055 } else if (name
== "key") {
1056 ia
->params
[agent::ptSearch
].key
= data
;
1058 ia
->params
[agent::ptSearch
].paramnames
.push_back(make_pair(name
, data
));
1061 if ((name
!= "item") && ia
->params
[agent::ptSearch
].paramnames
.empty())
1070 while(ia != jhook.agents.end()) {
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
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);
1101 void jabberhook::lookup(const imsearchparams
¶ms
, verticalmenu
&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);
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);
1138 } else if(!params
.room
.empty()) {
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
);
1152 log(logConfMembers
, foundguys
.size());
1154 searchdest
->redraw();
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
));
1167 ir
->second
= newname
;
1175 void jabberhook::ouridchanged(const icqconf::imaccount
&ia
) {
1177 setautostatus(ourstatus
);
1178 // send a new presence
1182 // ----------------------------------------------------------------------------
1184 void jabberhook::gotsearchresults(xmlnode x
) {
1186 const char *jid
, *nick
, *first
, *last
, *email
;
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
);
1203 c
= new icqcontact(imcontact(jidnormalize(jid
), proto
));
1204 icqcontact::basicinfo cb
= c
->getbasicinfo();
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
);
1230 log(logSearchFinished
, foundguys
.size());
1232 searchdest
->redraw();
1236 void jabberhook::gotloggedin() {
1241 // x = jutil_iqnew(JPACKET__GET, NS_AGENTS);
1242 // xmlnode_put_attrib(x, "id", "Agent List");
1246 char *server
= strdup(jc
->user
->server
);
1248 jhook
.agents
.push_back(agent(server
, server
, "", agent::atUnknown
));
1251 x
= jutil_iqnew(JPACKET__GET
, NS_DISCOINFO
);
1253 ignore_ids
.insert((string
)id
);
1254 xmlnode_put_attrib(x
, "id", id
);
1255 xmlnode_put_attrib(x
, "to", server
);
1259 x
= jutil_iqnew(JPACKET__GET
, NS_DISCOITEMS
);
1261 ignore_ids
.insert((string
)id
);
1262 xmlnode_put_attrib(x
, "id", id
);
1263 xmlnode_put_attrib(x
, "to", server
);
1269 x
= jutil_iqnew(JPACKET__GET
, NS_ROSTER
);
1270 xmlnode_put_attrib(x
, "id", "Roster");
1275 void jabberhook::gotroster(xmlnode x
) {
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
) : "";
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 {
1298 jidsplit(alias
, u
, h
, r
);
1302 c
->setdispnick(jidtodisp(alias
));
1306 roster
[jidnormalize(alias
)] = grp
;
1313 void jabberhook::postlogin() {
1317 ourstatus
= available
;
1318 time(&timer_keepalive
);
1321 setautostatus(jhook
.manualstatus
);
1324 for(i
= 0; i
< clist
.count
; i
++) {
1325 c
= (icqcontact
*) clist
.at(i
);
1327 if(c
->getdesc().pname
== proto
)
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;
1337 ifstream
f(conf
->getconfigfname("jabber-infoset").c_str());
1340 icqcontact
*c
= clist
.get(contactroot
);
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
;
1353 c
->setbasicinfo(bi
);
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);
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");
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
®ion
, 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
) {
1401 icqcontact::reginfo ri
= c
.getreginfo();
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());
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
);
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);
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
))) {
1497 if(!r
.empty()) body
.insert(0, r
+ ": ");
1501 icqcontact
*c
= clist
.get(ic
);
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
1511 else c
->setusepgpkey(false);
1513 c
->setusepgpkey(false);
1519 if (!otr
.receive_message(proto
, from
, body
)) return;
1522 em
.store(immessage(ic
, imevent::incoming
, rusconv("uk", body
)));
1525 void jabberhook::updatecontact(icqcontact
*c
) {
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);
1551 void jabberhook::gotvcard(const imcontact
&ic
, xmlnode v
) {
1555 bool wasrole
= false;
1557 icqcontact
*c
= clist
.get(ic
);
1558 if(!c
|| isourid(ic
.nickname
)) c
= clist
.get(contactroot
);
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
;
1581 if(name
== "TITLE" || name
== "ROLE") {
1587 if(!wi
.position
.empty()) wi
.position
+= " / ";
1588 wi
.position
+= data
;
1591 bi
.fname
= getword(data
);
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());
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
);
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
);
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
);
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"))
1649 if( get_img_ext(p
, ext
) )
1651 contact_dir
+= (string
)"." + ext
;
1652 if(p
= xmlnode_get_tag_data(ad
, "BINVAL")) {
1654 char *ptr
= base64_decode( p
, &len
);
1657 int ggg
= open(contact_dir
.c_str(), O_CREAT
| O_WRONLY
| O_TRUNC
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
1660 write(ggg
, ptr
, len
);
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
;
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
);
1687 if(isourid(ic
.nickname
)) {
1688 icqcontact
*cc
= clist
.get(ic
);
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());
1715 void jabberhook::sendversion(const imcontact
&ic
, xmlnode i
) {
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 );
1731 if(conf
->getourid(jhook
.proto
).additional
["osinfo"] == "1")
1734 if( !uname( &buf
) )
1736 string os
= buf
.sysname
;
1739 y
= xmlnode_insert_tag(xmlnode_get_tag(x
,"query"), "os");
1740 xmlnode_insert_cdata(y
, os
.c_str(), (unsigned) -1 );
1748 void jabberhook::gotversion(const imcontact
&ic
, xmlnode x
) { //fix version parsing
1749 xmlnode y
= xmlnode_get_tag(x
, "query"), z
;
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
);
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
) {
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
);
1826 bool jabberhook::isourid(const string
&jid
) {
1827 icqconf::imaccount acc
= conf
->getourid(jhook
.proto
);
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
;
1842 if(jid
.find("@") == -1)
1843 jid
+= (string
) "@" + acc
.server
;
1845 if((pos
= jid
.find(":")) != -1)
1848 if(jid
.find("/") == -1)
1849 jid
+= "/centerim" + jhook
.uuid
;
1854 imstatus
jabberhook::process_presence(string id
, string s
, char prio
, imstatus ust
)
1856 if (statuses
.find(id
) == statuses
.end()) { // new and only presence
1858 (statuses
[id
])[s
] = pair
<char, imstatus
>(prio
, ust
);
1860 if (statuses
[id
].find(s
) == statuses
[id
].end()) { // unknown resource
1862 (statuses
[id
])[s
] = pair
<char, imstatus
>(prio
, ust
);
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
]);
1875 // ----------------------------------------------------------------------------
1877 void jabberhook::statehandler(jconn conn
, int state
) {
1878 static int previous_state
= -1;
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
);
1895 case JCONN_STATE_CONNECTED
:
1898 case JCONN_STATE_AUTH
:
1901 case JCONN_STATE_ON
:
1902 if(jhook
.regmode
) jhook
.fonline
= true;
1909 previous_state
= state
;
1912 void jabberhook::packethandler(jconn conn
, jpacket packet
) {
1915 string from
, type
, body
, enc
, ns
, id
, u
, h
, s
, packet_id
;
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
)) {
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);
1982 if(type
== "result") {
1983 if(p
= xmlnode_get_attrib(packet
->x
, "id")) {
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")) {
1994 jhook
.id
= atoi(jab_auth(jhook
.jc
));
1995 jhook
.jstate
= STATE_SENDAUTH
;
1998 jhook
.gotloggedin();
1999 jhook
.jstate
= STATE_LOGGED
;
2003 jhook
.regdone
= true;
2009 if(!strcmp(p
, "VCARDreq")) {
2010 x
= xmlnode_get_firstchild(packet
->x
);
2011 if(!x
) x
= packet
->x
;
2013 jhook
.gotvcard(ic
, x
);
2016 } else if(!strcmp(p
, "versionreq")) {
2017 jhook
.gotversion(ic
, packet
->x
);
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
) {
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");
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");
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");
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");
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
);
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
);
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
);
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");
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
;
2139 jhook
.getfile_byte(ic
, packet
->x
);
2143 else if(!strcmp(p
, NS_OOB
)) {
2144 jhook
.full_jids
[ic
.nickname
] = from
;
2146 jhook
.getfile_http(ic
, packet
->x
);
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
;
2162 jhook
.file_transfer_request(ic
, packet
->x
);
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");
2181 } else if(type
== "error") {
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
);
2197 case 501: /* Not Implemented */
2199 jhook
.regerr
= desc
;
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 */
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
);
2230 jhook
.regerr
= desc
;
2238 case JPACKET_PRESENCE
:
2239 if (type
== "error")
2241 if(!jhook
.regmode
) {
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());
2254 x
= xmlnode_get_tag(packet
->x
, "show");
2258 p
= xmlnode_get_data(x
); if(p
) ns
= p
;
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")
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
);
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());
2295 icqcontact
*c
= clist
.get(ic
);
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());
2310 jhook
.agents
.push_back(agent(from
, "", "", agent::atUnknown
));
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)*/
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
);
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
);
2344 unsigned char hashval
[20];
2347 shaBlock((unsigned char *)hash
, file_size
, hashval
);
2352 snprintf(pos
, 3, "%02x", hashval
[k
]);
2355 if( strcmp( p
, final
) != 0 )
2356 jhook
.requestinfo(c
);
2360 jhook
.requestinfo(c
);
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
]));
2377 isagent
= find(jhook
.agents
.begin(), jhook
.agents
.end(), from
) != jhook
.agents
.end();
2379 if(type
== "subscribe") {
2381 em
.store(imauthorization(ic
, imevent::incoming
,
2382 imauthorization::Request
, _("The user wants to subscribe to your network presence updates")));
2385 char *cfrom
= strdup(from
.c_str());
2386 x
= jutil_presnew(JPACKET__SUBSCRIBED
, cfrom
, 0);
2387 jab_send(jhook
.jc
, x
);
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
);
2397 em
.store(imnotification(ic
, _("The user has removed you from his contact list (unsubscribed you, using the Jabber language)")));
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";
2420 bool jabberhook::get_img_ext(const string
&type
, string
&ext
) {
2423 if(type
.find("image/") != -1) {
2424 if((pos
= type
.find("/")) != -1) {
2425 ext
= type
.substr(pos
+1);
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
;
2445 contact_dir
= bi
.avatar
;
2446 string image_type
= contact_dir
;
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 )
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
);
2463 free(avatar_stream
);
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
;
2483 contact_dir
= bi
.avatar
;
2484 int ava_file
= open( contact_dir
.c_str(), O_RDONLY
);
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
);
2494 unsigned char hashval
[20];
2497 shaBlock((unsigned char *)hash
, file_size
, hashval
);
2502 snprintf(pos
, 3, "%02x", hashval
[k
]);
2513 bool jabberhook::url_port_get(const string
&full_url
, string
&url
, int &port
, string
&tail
, string
&filename
) {
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
);
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/
2542 void jabberhook::send_file(const string
&cjid
) //http sendfile
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
;
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 );
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 );
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
;
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
);
2596 if(file
->transfer_type
== 0) //socks5 file transfer
2597 jhook
.bytenegotiat(fr
);
2598 if(file
->transfer_type
== 1) //http file transfer
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
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
];
2640 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
, icqface::tsProgress
, size
, bytes
);
2643 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
, icqface::tsFinish
, size
, 0);
2644 jhook
.clean_up_file(fr
, 0);
2647 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
, icqface::tsError
, 0, 0);
2648 jhook
.clean_up_file(fr
, 0);
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
)
2666 face
.transferupdate(files
[ir
].fname
, fr
, icqface::tsProgress
, size
, bytes
);
2669 face
.transferupdate(files
[ir
].fname
, fr
, icqface::tsFinish
, size
, 0);
2671 jhook
.srfiles
[jid
].second
.second
++;
2672 if( files
.size() > ir
)
2673 jhook
.send_file(jid
);
2675 jhook
.clean_up_file(fr
, 1, jid
);
2678 face
.transferupdate(files
[ir
].fname
, fr
, icqface::tsError
, 0, 0);
2679 jhook
.clean_up_file(fr
, 1, jid
);
2687 void jabberhook::file_transfer_request(const imcontact
&ic
, xmlnode i
) { //stream initialization request xep-0066
2689 char *filename
, *filesize
, *id
;
2692 p
= xmlnode_get_attrib(i
, "id");
2698 x
= xmlnode_get_tag(i
, "si");
2699 z
= xmlnode_get_tag(x
, "file");
2701 p
= xmlnode_get_attrib(z
, "name");
2707 p
= xmlnode_get_attrib(z
, "size");
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;
2725 //get filename and filesize from request
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
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 );
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
);
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
;
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
);
2812 void jabberhook::getfile_http(const imcontact
&ic
, xmlnode i
) { //xep-0066
2814 string full_url
, host
, url
, filename
;
2821 p
= xmlnode_get_attrib(i
, "id");
2827 x
= xmlnode_get_tag(i
, "query");
2828 y
= xmlnode_get_tag(x
, "url");
2829 p
= xmlnode_get_data(y
);
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;
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
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
;
2871 if( file
->transfer_type
== 0 )//bytestream method
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
);
2878 else if( file
->transfer_type
== 1 )//http GET method
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
);
2888 //parse bytestream xmpp request
2889 void jabberhook::getfile_byte(const imcontact
&ic
, xmlnode i
) {
2891 char *host
, *jid
, *sid
;
2897 x
= xmlnode_get_tag(i
, "query"), z
;
2898 p
= xmlnode_get_attrib(x
, "sid");
2904 z
= xmlnode_get_tag(x
, "streamhost");
2905 p
= xmlnode_get_attrib(z
, "host");
2911 p
= xmlnode_get_attrib(z
, "jid");
2917 p
= xmlnode_get_attrib(z
, "port");
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() );
2930 file
->host
= strdup( host
);
2936 void jabberhook::clean_up_file(const imfile
&fr
, int trans_type
, char *cjid
)
2939 struct send_file
*file
;
2942 if(transferinfo
.find(fr
) != transferinfo
.end())
2943 file
= (struct send_file
*)transferinfo
[fr
].first
;
2947 else if(trans_type
== 1)
2951 if(srfiles
.find(cjid
) != srfiles
.end())
2952 file
= (struct send_file
*)srfiles
[cjid
].second
.first
;
2962 pthread_cancel(file
->thread
);
2964 if(file
->full_jid_name
)
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
);
2978 if(file
->sid_from_to
)
2979 free(file
->sid_from_to
);
2982 transferinfo
[fr
].first
= NULL
;
2983 else if (trans_type
== 1)
2984 srfiles
[cjid
].second
.first
= NULL
;
2987 transferinfo
.erase(fr
);
2989 srfiles
.erase(cjid
);