Updating ChangeLog for 4.22.10
[centerim.git] / src / hooks / icqhook.cc
blob44e0bdbbb03a9f17fe2da0ad3a4a63f0e8e8bd0d
1 /*
3 * centerim icq protocol handling class
4 * $Id: icqhook.cc,v 1.159 2004/12/20 00:54:02 konst Exp $
6 * Copyright (C) 2001-2004 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_ICQ
29 #include "icqhook.h"
30 #include "icqconf.h"
31 #include "icqface.h"
32 #include "imlogger.h"
33 #include "icqgroups.h"
34 #include "icqcontacts.h"
35 #include "impgp.h"
37 #include "accountmanager.h"
38 #include "eventmanager.h"
40 #include "src/Capabilities.h"
42 #define PERIOD_ICQPOLL 5
43 #define PERIOD_RESOLVE 10
44 #define DELAY_SENDNEW 5
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
49 icqhook ihook;
51 static const Status stat2int[imstatus_size] = {
52 STATUS_OFFLINE,
53 STATUS_ONLINE,
54 STATUS_ONLINE, /* invisible */
55 STATUS_FREEFORCHAT,
56 STATUS_DND,
57 STATUS_OCCUPIED,
58 STATUS_NA,
59 STATUS_AWAY,
60 STATUS_NA
63 icqhook::icqhook(): abstracthook(icq) {
64 fonline = false;
65 blockmode = Normal;
67 fcapabs.insert(hookcapab::urls);
68 fcapabs.insert(hookcapab::setaway);
69 fcapabs.insert(hookcapab::fetchaway);
70 fcapabs.insert(hookcapab::changenick);
71 // fcapabs.insert(hookcapab::changepassword);
72 fcapabs.insert(hookcapab::changedetails);
73 fcapabs.insert(hookcapab::authrequests);
74 fcapabs.insert(hookcapab::authreqwithmessages);
75 fcapabs.insert(hookcapab::contacts);
76 fcapabs.insert(hookcapab::visibility);
77 fcapabs.insert(hookcapab::cltemporary);
78 fcapabs.insert(hookcapab::changeabout);
80 #ifdef HAVE_GPGME
81 fcapabs.insert(hookcapab::pgp);
82 #endif
84 cli.connected.connect(this, &icqhook::connected_cb);
85 cli.disconnected.connect(this, &icqhook::disconnected_cb);
86 cli.socket.connect(this, &icqhook::socket_cb);
87 cli.messaged.connect(this, &icqhook::messaged_cb);
88 cli.messageack.connect(this, &icqhook::messageack_cb);
89 cli.contactlist.connect(this, &icqhook::contactlist_cb);
90 cli.contact_userinfo_change_signal.connect(this, &icqhook::contact_userinfo_change_signal_cb);
91 cli.contact_status_change_signal.connect(this, &icqhook::contact_status_change_signal_cb);
92 cli.contact_typing_signal.connect(this, &icqhook::contact_typing_signal_cb);
93 cli.newuin.connect(this, &icqhook::newuin_cb);
94 cli.rate.connect(this, &icqhook::rate_cb);
95 // cli.password_changed.connect(this, &icqhook::password_changed_cb);
96 cli.want_auto_resp.connect(this, &icqhook::want_auto_resp_cb);
97 cli.search_result.connect(this, &icqhook::search_result_cb);
98 cli.self_contact_userinfo_change_signal.connect(this, &icqhook::self_contact_userinfo_change_cb);
99 cli.self_contact_status_change_signal.connect(this, &icqhook::self_contact_status_change_cb);
100 cli.sbl_received.connect(this, &icqhook::sbl_received_cb);
103 icqhook::~icqhook() {
104 cli.logger.disconnect(this);
105 cli.connected.disconnect(this);
106 cli.disconnected.disconnect(this);
107 cli.socket.disconnect(this);
108 cli.messaged.disconnect(this);
109 cli.messageack.disconnect(this);
110 cli.contactlist.disconnect(this);
111 cli.contact_userinfo_change_signal.disconnect(this);
112 cli.contact_status_change_signal.disconnect(this);
113 cli.newuin.disconnect(this);
114 cli.rate.disconnect(this);
115 cli.search_result.disconnect(this);
116 cli.want_auto_resp.disconnect(this);
117 cli.self_contact_userinfo_change_signal.disconnect(this);
118 cli.self_contact_status_change_signal.disconnect(this);
119 // cli.password_changed.disconnect(this);
122 void icqhook::init() {
123 manualstatus = conf->getstatus(proto);
125 if(conf->getdebug())
126 cli.logger.connect(this, &icqhook::logger_cb);
129 void icqhook::connect() {
130 icqconf::imaccount acc = conf->getourid(proto);
131 int i, ptpmin, ptpmax;
132 icqcontact *c;
134 if(acc.additional["webaware"].empty()) acc.additional["webaware"] = "1";
135 conf->setourid(acc);
137 if(!acc.server.empty()) cli.setLoginServerHost(acc.server);
138 if(acc.port) cli.setLoginServerPort(acc.port);
140 if(!conf->getsmtphost().empty()) cli.setSMTPServerHost(conf->getsmtphost());
141 if(conf->getsmtpport()) cli.setSMTPServerPort(conf->getsmtpport());
143 if(!conf->getbindhost().empty()) cli.setClientBindHost(conf->getbindhost());
145 conf->getpeertopeer(ptpmin, ptpmax);
146 if(ptpmax) {
147 cli.setAcceptInDC(true);
148 cli.setPortRangeLowerBound(ptpmin);
149 cli.setPortRangeUpperBound(ptpmax);
150 cli.setUsePortRange(true);
151 } else {
152 cli.setAcceptInDC(false);
155 log(logConnecting);
157 cli.self_contact_userinfo_change_signal.disconnect(this);
159 cli.setUIN(acc.uin);
160 cli.setPassword(acc.password);
161 cli.setWebAware(acc.additional["webaware"] == "1");
163 cli.setStatus(stat2int[manualstatus], manualstatus == invisible);
164 cli.self_contact_userinfo_change_signal.connect(this, &icqhook::self_contact_userinfo_change_cb);
166 for(i = 0; i < clist.count; i++) {
167 c = (icqcontact *) clist.at(i);
169 if(c->getdesc().pname == proto && c->getdesc().uin) {
170 icqcontact::basicinfo bi = c->getbasicinfo();
171 bi.authawait = true;
172 c->setbasicinfo(bi);
174 addContact(c->getdesc().uin, groups.getname(c->getgroupid()));
178 sendinvisible();
180 fonline = true;
181 flogged = false;
184 void icqhook::disconnect() {
185 cli.setStatus(STATUS_OFFLINE);
186 fonline = flogged = false;
189 void icqhook::resolve() {
190 icqcontact *c;
191 vector<icqcontact *> toresolve;
193 for(int i = 0; i < clist.count; i++) {
194 c = (icqcontact *) clist.at(i);
196 if(c->getdesc().pname == proto)
197 if(c->getdispnick() == i2str(c->getdesc().uin))
198 toresolve.push_back(c);
201 if(toresolve.size()) {
202 c = toresolve[randlimit(0, toresolve.size()-1)];
203 requestinfo(c);
207 void icqhook::sendinvisible() {
208 vector<visInfo> todo, nvislist;
209 vector<visInfo>::iterator iv, it;
210 icqlist::iterator i;
212 for(i = lst.begin(); i != lst.end(); ++i) {
213 if(i->getdesc().pname == proto) {
214 switch(i->getstatus()) {
215 case csvisible:
216 case csinvisible:
217 todo.push_back(pair<unsigned int, contactstatus>
218 (i->getdesc().uin, i->getstatus()));
219 break;
224 nvislist = todo;
226 for(iv = vislist.begin(); iv != vislist.end(); ++iv) {
227 it = find(todo.begin(), todo.end(), *iv);
229 if(it != todo.end()) {
230 todo.erase(it);
231 } else {
232 switch(iv->second) {
233 case csvisible: cli.removeVisible(iv->first); break;
234 case csinvisible: cli.removeInvisible(iv->first); break;
239 for(it = todo.begin(); it != todo.end(); ++it) {
240 switch(it->second) {
241 case csvisible: cli.addVisible(new Contact(it->first)); break;
242 case csinvisible: cli.addInvisible(new Contact(it->first)); break;
246 vislist = nvislist;
249 void icqhook::exectimers() {
250 if(logged()) {
251 if(timer_current-timer_poll > PERIOD_ICQPOLL) {
252 cli.Poll();
253 sendinvisible();
254 timer_poll = timer_current;
258 * Will to the mass-adding stuff here too..
262 vector<imcontact>::iterator ic = uinstosend.begin();
264 if(ic != uinstosend.end()) {
265 imcontact imc = *ic;
266 uinstosend.erase(ic);
268 ContactRef icont = cli.getContact(imc.uin);
269 if(!icont.get()) sendnewuser(imc);
273 if(timer_current-timer_resolve > PERIOD_RESOLVE) {
274 resolve();
275 timer_resolve = timer_current;
280 void icqhook::main() {
281 vector<int>::iterator i;
282 struct timeval tv;
283 int hsock;
284 fd_set rs, ws, es;
286 FD_ZERO(&rs);
287 FD_ZERO(&ws);
288 FD_ZERO(&es);
290 tv.tv_sec = tv.tv_usec = 0;
291 hsock = 0;
293 for(i = rfds.begin(); i != rfds.end(); ++i) {
294 FD_SET(*i, &rs);
295 hsock = max(hsock, *i);
298 for(i = wfds.begin(); i != wfds.end(); ++i) {
299 FD_SET(*i, &ws);
300 hsock = max(hsock, *i);
303 for(i = efds.begin(); i != efds.end(); ++i) {
304 FD_SET(*i, &es);
305 hsock = max(hsock, *i);
308 if(select(hsock+1, &rs, &ws, &es, &tv) > 0) {
309 for(i = rfds.begin(); i != rfds.end(); ++i) {
310 if(FD_ISSET(*i, &rs)) {
311 cli.socket_cb(*i, SocketEvent::READ);
312 break;
316 for(i = wfds.begin(); i != wfds.end(); ++i) {
317 if(FD_ISSET(*i, &ws)) {
318 cli.socket_cb(*i, SocketEvent::WRITE);
319 break;
323 for(i = efds.begin(); i != efds.end(); ++i) {
324 if(FD_ISSET(*i, &es)) {
325 cli.socket_cb(*i, SocketEvent::EXCEPTION);
326 break;
332 void icqhook::getsockets(fd_set &rs, fd_set &ws, fd_set &es, int &hsocket) const {
333 vector<int>::const_iterator i;
335 for(i = rfds.begin(); i != rfds.end(); ++i) {
336 hsocket = max(hsocket, *i);
337 FD_SET(*i, &rs);
340 for(i = wfds.begin(); i != wfds.end(); ++i) {
341 hsocket = max(hsocket, *i);
342 FD_SET(*i, &ws);
345 for(i = efds.begin(); i != efds.end(); ++i) {
346 hsocket = max(hsocket, *i);
347 FD_SET(*i, &es);
351 bool icqhook::isoursocket(fd_set &rs, fd_set &ws, fd_set &es) const {
352 vector<int>::const_iterator i;
354 for(i = rfds.begin(); i != rfds.end(); ++i)
355 if(FD_ISSET(*i, &rs))
356 return true;
358 for(i = wfds.begin(); i != wfds.end(); ++i)
359 if(FD_ISSET(*i, &ws))
360 return true;
362 for(i = efds.begin(); i != efds.end(); ++i)
363 if(FD_ISSET(*i, &es))
364 return true;
366 return false;
369 bool icqhook::online() const {
370 return fonline;
373 bool icqhook::logged() const {
374 return fonline && flogged;
377 bool icqhook::isconnecting() const {
378 return fonline && !flogged;
381 bool icqhook::enabled() const {
382 return true;
385 bool icqhook::send(const imevent &ev) {
386 unsigned int uin = ev.getcontact().uin;
387 ContactRef ic = cli.getContact(uin);
388 MessageEvent *sev = 0;
389 ICQMessageEvent *iev;
390 icqcontact *c=clist.get(ev.getcontact());
392 if(ev.getcontact().pname != proto)
393 uin = 0;
395 if(!uin)
396 ic = cli.getSelfContact();
398 if(!ic.get())
399 return false;
401 if(ev.gettype() == imevent::message) {
402 const immessage *m = static_cast<const immessage *> (&ev);
403 string text = m->gettext(), sub;
405 #ifdef HAVE_GPGME
406 if ( (c!=NULL) && (pgp.enabled(ev.getcontact())) ) {
407 text = pgp.encrypt(text, c->getpgpkey(), proto);
408 text = "-----BEGIN PGP MESSAGE-----\n\n" + text + "\n-----END PGP MESSAGE-----\n";
410 #endif
412 if(ic->getStatus() == STATUS_OFFLINE)
413 if(text.size() > 450) {
414 while(!text.empty()) {
415 if(text.size() > 450) {
416 sub = text.substr(0, 450);
417 text.erase(0, 450);
418 } else {
419 sub = text;
420 text = "";
423 cli.SendEvent(new NormalMessageEvent(ic, ruscrlfconv("kw", sub)));
426 return true;
429 sev = new NormalMessageEvent(ic, ruscrlfconv("kw", text));
431 } else if(ev.gettype() == imevent::url) {
432 const imurl *m = static_cast<const imurl *> (&ev);
433 sev = new URLMessageEvent(ic,
434 ruscrlfconv("kw", m->getdescription()),
435 ruscrlfconv("kw", m->geturl()));
437 } else if(ev.gettype() == imevent::sms) {
438 const imsms *m = static_cast<const imsms *> (&ev);
440 if(!uin) {
441 if(m->getphone().empty()) {
442 if(ic->getMainHomeInfo().getMobileNo().empty()) {
443 cli.fetchSelfDetailContactInfo();
444 return false;
446 } else {
447 ic = new Contact(m->getphone());
448 ic->setMobileNo(m->getphone());
450 ContactTree &ct = cli.getContactTree();
451 ContactTree::Group &g = ct.group_size() ? *ct.begin() : ct.add_group("New");
452 g.add(ic);
455 } else {
456 cli.contact_userinfo_change_signal.disconnect(this);
457 ic->setMobileNo(clist.get(ev.getcontact())->getbasicinfo().cellular);
458 cli.contact_userinfo_change_signal.connect(this, &icqhook::contact_userinfo_change_signal_cb);
461 sev = new SMSMessageEvent(ic, rusconv("ku", m->getmessage()), true);
463 } else if(ev.gettype() == imevent::authorization) {
464 const imauthorization *m = static_cast<const imauthorization *> (&ev);
466 switch(m->getauthtype()) {
467 case imauthorization::Granted:
468 case imauthorization::Rejected:
469 sev = new AuthAckEvent(ic, ruscrlfconv("kw", m->getmessage()),
470 m->getauthtype() == imauthorization::Granted);
471 break;
473 case imauthorization::Request:
474 sev = new AuthReqEvent(ic, ruscrlfconv("kw", m->getmessage()));
475 if(c != NULL) {
476 icqcontact::basicinfo bi = c->getbasicinfo();
477 bi.authawait = true;
478 c->setbasicinfo(bi);
480 break;
483 } else if(ev.gettype() == imevent::contacts) {
484 const imcontacts *m = static_cast<const imcontacts *> (&ev);
485 vector< pair<unsigned int, string> >::const_iterator icc;
486 list<ContactRef> slst;
488 for(icc = m->getcontacts().begin(); icc != m->getcontacts().end(); ++icc) {
489 ContactRef ct(new Contact(icc->first));
490 ct->setAlias(ruscrlfconv("kw", icc->second));
491 slst.push_back(ct);
494 sev = new ContactMessageEvent(ic, slst);
496 } else {
497 return false;
500 if(sev) {
501 if(ic->getStatus() == STATUS_DND || ic->getStatus() == STATUS_OCCUPIED)
502 if(iev = dynamic_cast<ICQMessageEvent *>(sev))
503 iev->setUrgent(true);
505 cli.SendEvent(sev);
508 return true;
511 void icqhook::sendnewuser(const imcontact &ic) {
512 static time_t lastadd = 0;
513 icqcontact *cc = clist.get(ic);
515 if(logged() && ic.uin && cc) {
516 if(timer_current-lastadd > DELAY_SENDNEW) {
517 ContactRef cont = addContact(ic.uin, groups.getname(cc->getgroupid()));
518 cli.fetchSimpleContactInfo(cont);
519 cli.fetchDetailContactInfo(cont);
521 if(sblrecv && cc->inlist()) {
522 ContactTree::Group &g = cli.getContactTree().lookup_group_containing_contact(cont);
524 cont->setServerSideInfo(g.get_id(), 0);
525 cont->setServerBased(true);
526 cont->setAuthAwait(cc->getbasicinfo().authawait);
528 //cli.uploadServerBasedContact(cont);
531 lastadd = timer_current;
533 } else {
534 uinstosend.push_back(ic);
540 void icqhook::removeuser(const imcontact &c) {
541 ContactRef ic = cli.getContact(c.uin);
543 if(ic.get()) {
544 icqcontact *cc = clist.get(c);
546 if(cc)
547 if(cc->inlist()) {
548 if(ic->getServerBased()) {
549 ic->setAlias(cc->getnick());
550 ic->setAuthAwait(cc->getbasicinfo().authawait);
551 //cli.removeServerBasedContact(ic);
555 ContactTree& ct = cli.getContactTree();
556 ContactTree::Group &gr = ct.lookup_group_containing_contact(ic);
557 gr.remove(c.uin);
561 void icqhook::setautostatus(imstatus st) {
562 if(st != offline) {
563 if(getstatus() == offline) {
564 connect();
565 } else {
566 sendinvisible();
567 logger.putourstatus(icq, getstatus(), st);
568 cli.setStatus(stat2int[st], st == invisible);
570 } else {
571 if(getstatus() != offline) {
572 disconnect();
577 imstatus icqhook::getstatus() const {
578 if(!fonline) {
579 return offline;
580 } else if(cli.getInvisible()) {
581 return invisible;
582 } else {
583 return icq2imstatus(cli.getStatus());
587 bool icqhook::regconnect(const string &aserv) {
588 int pos;
590 if((pos = aserv.find(":")) != -1) {
591 cli.setLoginServerHost(aserv.substr(0, pos));
592 cli.setLoginServerPort(strtoul(aserv.substr(pos+1).c_str(), 0, 0));
595 return true;
598 bool icqhook::regattempt(unsigned int &auin, const string &apassword, const string &email) {
599 fd_set srfds, swfds, sefds;
600 struct timeval tv;
601 int hsockfd;
602 time_t regtimeout = time(0);
604 reguin = 0;
606 cli.setPassword(apassword);
607 cli.RegisterUIN();
609 while(!reguin && (time(0)-regtimeout < 60)) {
610 hsockfd = 0;
612 FD_ZERO(&srfds);
613 FD_ZERO(&swfds);
614 FD_ZERO(&sefds);
616 getsockets(srfds, swfds, sefds, hsockfd);
618 tv.tv_sec = 30;
619 tv.tv_usec = 0;
621 select(hsockfd+1, &srfds, &swfds, &sefds, &tv);
623 if(isoursocket(srfds, swfds, sefds)) {
624 main();
628 auin = reguin;
629 return (bool) reguin;
632 imstatus icqhook::icq2imstatus(const Status st) const {
633 switch(st) {
634 case STATUS_AWAY:
635 return away;
636 case STATUS_NA:
637 return notavail;
638 case STATUS_OCCUPIED:
639 return occupied;
640 case STATUS_DND:
641 return dontdisturb;
642 case STATUS_FREEFORCHAT:
643 return freeforchat;
644 case STATUS_OFFLINE:
645 return offline;
646 case STATUS_ONLINE:
647 default:
648 return available;
652 void icqhook::requestinfo(const imcontact &c) {
653 if(logged() && c.uin) {
654 if(c == imcontact(conf->getourid(icq).uin, icq)) {
655 // Our info is requested
656 cli.fetchSelfDetailContactInfo();
657 } else {
658 ContactRef icont = cli.getContact(c.uin);
660 if(!icont.get()) {
661 addContact(c.uin, "");
662 } else {
663 cli.fetchSimpleContactInfo(icont);
664 cli.fetchDetailContactInfo(icont);
670 void icqhook::lookup(const imsearchparams &params, verticalmenu &dest) {
671 ICQ2000::Sex sex;
673 while(!foundguys.empty()) {
674 delete foundguys.back();
675 foundguys.pop_back();
678 searchdest = &dest;
680 sex = params.gender == genderMale ? ICQ2000::SEX_MALE :
681 params.gender == genderFemale ? ICQ2000::SEX_FEMALE :
682 ICQ2000::SEX_UNKNOWN;
684 if(params.uin) {
685 searchevent = cli.searchForContacts(params.uin);
687 } else if(!params.kwords.empty()) {
688 searchevent = cli.searchForContacts(rusconv("kw", params.kwords));
690 } else if(params.randomgroup) {
691 searchevent = cli.searchForContacts((ICQ2000::RandomChatGroup) params.randomgroup);
693 } else if(!params.email.empty() || params.minage || params.maxage ||
694 !params.city.empty() || !params.state.empty() ||
695 !params.company.empty() || !params.department.empty() ||
696 !params.position.empty() || params.onlineonly ||
697 params.country || params.language ||
698 (sex != SEX_UNKNOWN) || (params.agerange != RANGE_NORANGE)) {
699 searchevent = cli.searchForContacts(rusconv("kw", params.nick),
700 rusconv("kw", params.firstname), rusconv("kw", params.lastname),
701 rusconv("kw", params.email), params.agerange, sex,
702 params.language, rusconv("kw", params.city),
703 rusconv("kw", params.state), params.country,
704 rusconv("kw", params.company), rusconv("kw", params.department),
705 rusconv("kw", params.position), params.onlineonly);
707 } else {
708 searchevent = cli.searchForContacts(rusconv("kw", params.nick),
709 rusconv("kw", params.firstname), rusconv("kw", params.lastname));
714 void icqhook::sendupdateuserinfo(const icqcontact &c) {
715 ContactRef ic = cli.getSelfContact();
717 cli.self_contact_userinfo_change_signal.disconnect(this);
719 Contact::MainHomeInfo &home = ic->getMainHomeInfo();
720 Contact::HomepageInfo &hpage = ic->getHomepageInfo();
721 Contact::WorkInfo &work = ic->getWorkInfo();
723 const icqcontact::basicinfo &cbinfo = c.getbasicinfo();
724 const icqcontact::moreinfo &cminfo = c.getmoreinfo();
725 const icqcontact::workinfo &cwinfo = c.getworkinfo();
727 /* basic information */
729 ic->setAlias(rusconv("kw", c.getnick()));
730 ic->setFirstName(rusconv("kw", cbinfo.fname));
731 ic->setLastName(rusconv("kw", cbinfo.lname));
732 ic->setEmail(rusconv("kw", cbinfo.email));
733 ic->setAuthReq(cbinfo.requiresauth);
735 ic->setAboutInfo(rusconv("kw", c.getabout()));
737 home.city = rusconv("kw", cbinfo.city);
738 home.state = rusconv("kw", cbinfo.state);
739 home.phone = rusconv("kw", cbinfo.phone);
740 home.fax = rusconv("kw", cbinfo.fax);
741 home.street = rusconv("kw", cbinfo.street);
742 home.setMobileNo(rusconv("kw", cbinfo.cellular));
744 home.zip = cbinfo.zip;
745 home.country = (Country) cbinfo.country;
746 home.timezone = (Timezone) getSystemTimezone();
748 /* more information */
750 hpage.age = cminfo.age;
752 hpage.sex =
753 cminfo.gender == genderFemale ? SEX_FEMALE :
754 cminfo.gender == genderMale ? SEX_MALE :
755 SEX_UNKNOWN;
757 hpage.homepage = rusconv("kw", cminfo.homepage);
758 hpage.birth_day = cminfo.birth_day;
759 hpage.birth_month = cminfo.birth_month;
760 hpage.birth_year = cminfo.birth_year;
762 hpage.lang1 = (Language) cminfo.lang1;
763 hpage.lang2 = (Language) cminfo.lang2;
764 hpage.lang3 = (Language) cminfo.lang3;
766 /* work information */
768 work.city = rusconv("kw", cwinfo.city);
769 work.state = rusconv("kw", cwinfo.state);
770 work.street = rusconv("kw", cwinfo.street);
771 work.company_name = rusconv("kw", cwinfo.company);
772 work.company_dept = rusconv("kw", cwinfo.dept);
773 work.company_position = rusconv("kw", cwinfo.position);
774 work.company_web = rusconv("kw", cwinfo.homepage);
776 work.zip = cwinfo.zip;
777 work.country = cwinfo.country;
779 ic->setMainHomeInfo(home);
780 ic->setHomepageInfo(hpage);
781 ic->setWorkInfo(work);
782 ic->setAuthReq(cbinfo.requiresauth);
784 icqconf::imaccount acc = conf->getourid(icq);
785 acc.additional["webaware"] = cbinfo.webaware ? "1" : "0";
786 acc.additional["randomgroup"] = i2str(cbinfo.randomgroup);
787 conf->setourid(acc);
789 cli.setWebAware(cbinfo.webaware);
790 cli.setRandomChatGroup(cbinfo.randomgroup);
792 cli.uploadSelfDetails();
793 cli.self_contact_userinfo_change_signal.connect(this, &icqhook::self_contact_userinfo_change_cb);
795 if(!c.getreginfo().password.empty())
796 cli.changePassword(c.getreginfo().password);*/
799 void icqhook::requestawaymsg(const imcontact &c) {
800 ContactRef ic = cli.getContact(c.uin);
802 if(ic.get()) {
803 cli.SendEvent(new AwayMessageEvent(ic));
807 void icqhook::updateinforecord(ContactRef ic, icqcontact *c) {
808 string sbuf;
809 vector<string> pintinfo, backginfo;
810 list<Contact::PersonalInterestInfo::Interest>::iterator ii;
811 list<Contact::BackgroundInfo::School>::iterator isc;
812 icqcontact::basicinfo cbinfo;
813 icqcontact::moreinfo cminfo;
814 icqcontact::workinfo cwinfo;
816 if(ic.get() && c) {
817 Contact::MainHomeInfo &home = ic->getMainHomeInfo();
818 Contact::HomepageInfo &hpage = ic->getHomepageInfo();
819 Contact::WorkInfo &work = ic->getWorkInfo();
820 Contact::PersonalInterestInfo &pint = ic->getPersonalInterestInfo();
821 Contact::BackgroundInfo &backg = ic->getBackgroundInfo();
822 Contact::EmailInfo &email = ic->getEmailInfo();
824 cbinfo = c->getbasicinfo();
825 cminfo = c->getmoreinfo();
826 cwinfo = c->getworkinfo();
828 /* basic information */
830 cbinfo.fname = rusconv("wk", ic->getFirstName());
831 cbinfo.lname = rusconv("wk", ic->getLastName());
832 if(!ic->getEmail().empty()) cbinfo.email = rusconv("wk", ic->getEmail());
833 cbinfo.city = rusconv("wk", home.city);
834 cbinfo.state = rusconv("wk", home.state);
835 cbinfo.phone = rusconv("wk", home.phone);
836 cbinfo.fax = rusconv("wk", home.fax);
837 cbinfo.street = rusconv("wk", home.street);
838 cbinfo.requiresauth = ic->getAuthReq();
840 if(!home.getMobileNo().empty())
841 cbinfo.cellular = rusconv("wk", home.getMobileNo());
843 cbinfo.zip = home.zip;
844 cbinfo.country = home.country;
846 /* more information */
848 cminfo.age = hpage.age;
850 cminfo.gender =
851 hpage.sex == 1 ? genderFemale :
852 hpage.sex == 2 ? genderMale :
853 genderUnspec;
855 cminfo.homepage = rusconv("wk", hpage.homepage);
856 cminfo.birth_day = hpage.birth_day;
857 cminfo.birth_month = hpage.birth_month;
858 cminfo.birth_year = hpage.birth_year;
860 cminfo.lang1 = hpage.lang1;
861 cminfo.lang2 = hpage.lang2;
862 cminfo.lang3 = hpage.lang3;
864 cminfo.timezone = home.timezone;
866 /* work information */
868 cwinfo.city = rusconv("wk", work.city);
869 cwinfo.state = rusconv("wk", work.state);
870 cwinfo.street = rusconv("wk", work.street);
871 cwinfo.company = rusconv("wk", work.company_name);
872 cwinfo.dept = rusconv("wk", work.company_dept);
873 cwinfo.position = rusconv("wk", work.company_position);
874 cwinfo.homepage = rusconv("wk", work.company_web);
876 cwinfo.zip = work.zip;
877 cwinfo.country = work.country;
879 /* personal interests */
881 for(ii = pint.interests.begin(); ii != pint.interests.end(); ++ii) {
882 sbuf = getInterestsIDtoString(ii->first);
884 if(!ii->second.empty()) {
885 if(!sbuf.empty()) sbuf += ": ";
886 sbuf += rusconv("wk", ii->second);
889 if(!sbuf.empty()) pintinfo.push_back(sbuf);
892 /* education background */
894 for(isc = backg.schools.begin(); isc != backg.schools.end(); ++isc) {
895 sbuf = getBackgroundIDtoString(isc->first);
896 if(!sbuf.empty()) sbuf += ": ";
897 sbuf += rusconv("wk", isc->second);
898 if(!sbuf.empty()) backginfo.push_back(sbuf);
901 /* nicknames stuff */
903 string nick = rusconv("wk", ic->getAlias());
905 if((c->getnick() == c->getdispnick())
906 || (c->getdispnick() == i2str(c->getdesc().uin))) {
907 c->setdispnick(nick);
910 c->setnick(nick);
911 c->setbasicinfo(cbinfo);
912 c->setmoreinfo(cminfo);
913 c->setworkinfo(cwinfo);
914 c->setinterests(pintinfo);
915 c->setbackground(backginfo);
916 c->setabout(rusconv("wk", ic->getAboutInfo()));
918 face.relaxedupdate();
922 void icqhook::processemailevent(const string &sender, const string &email, const string &message) {
923 if(email.empty() && sender.empty() && message.empty())
924 return;
926 icqcontact *c = clist.getemail(email);
928 if(!c)
929 if(c = clist.addnew(imcontact(0, infocard), true)) {
930 c->setdispnick(email);
931 c->setnick(email);
933 icqcontact::basicinfo b = c->getbasicinfo();
935 if(sender != email) {
936 int pos = sender.find(" ");
938 if(pos != -1) {
939 b.fname = sender.substr(0, pos);
940 b.lname = sender.substr(pos+1);
941 } else {
942 b.fname = sender;
946 b.email = email;
947 c->setbasicinfo(b);
950 if(c) {
951 em.store(imemail(c, imevent::incoming,
952 rusconv("wk", message)));
956 void icqhook::updatecontact(icqcontact *c) {
957 if(sblrecv) {
958 ContactTree &tree = cli.getContactTree();
959 ContactRef ic = tree[c->getdesc().uin];
961 if(ic.get()) {
962 string gname = groups.getname(c->getgroupid());
963 ContactTree::Group &oldg = tree.lookup_group_containing_contact(ic);
964 ContactTree::Group *newg = 0;
966 if(oldg.get_label() != gname) {
967 ContactTree::iterator curr = tree.begin();
968 while(curr != tree.end()) {
969 if((*curr).get_label() == gname) {
970 newg = &(*curr);
971 break;
973 ++curr;
976 //cli.removeServerBasedContact(ic);
978 if(!newg) newg = &(tree.add_group(gname));
979 tree.relocate_contact(ic, oldg, *newg);
981 ic->setServerSideInfo(newg->get_id(), ic->getServerSideID());
982 ic->setAuthAwait(c->getbasicinfo().authawait);
984 //cli.uploadServerBasedContact(ic);
990 void icqhook::renamegroup(const string &oldname, const string &newname) {
991 if(logged()) {
993 ContactTree::Group *gp = 0;
994 ContactTree &ct = cli.getContactTree();
996 ContactTree::iterator curr = ct.begin();
997 while(curr != ct.end()) {
998 if((*curr).get_label() == oldname) {
999 gp = &(*curr);
1000 break;
1002 ++curr;
1005 if(gp) {
1006 gp->set_label(newname);
1007 cli.uploadServerBasedGroup(*gp);
1013 // ----------------------------------------------------------------------------
1015 void icqhook::connected_cb(ConnectedEvent *ev) {
1016 flogged = true;
1018 timer_poll = timer_current;
1019 timer_resolve = timer_poll-PERIOD_RESOLVE+3;
1021 logger.putourstatus(icq, offline, manualstatus);
1023 cli.setRandomChatGroup(strtoul(conf->getourid(icq).additional["randomgroup"].c_str(), 0, 0));
1025 log(logLogged);
1026 face.update();
1028 string buf;
1029 ifstream f(conf->getconfigfname("icq-infoset").c_str());
1031 if(f.is_open()) {
1032 getstring(f, buf); cli.getSelfContact()->setAlias(buf);
1033 getstring(f, buf); cli.getSelfContact()->setEmail(buf);
1034 getstring(f, buf); cli.getSelfContact()->setFirstName(buf);
1035 getstring(f, buf); cli.getSelfContact()->setLastName(buf);
1036 f.close();
1038 cli.getSelfContact()->getMainHomeInfo().timezone = (Timezone) getSystemTimezone();
1039 cli.uploadSelfDetails();
1041 unlink(conf->getconfigfname("icq-infoset").c_str());
1044 cli.fetchServerBasedContactList();
1047 void icqhook::disconnected_cb(DisconnectedEvent *ev) {
1048 string msg;
1050 static const string reasons[DisconnectedEvent::FAILED_UNKNOWN+1] = {
1051 _("as requested"),
1052 _("socket problems"),
1053 _("bad username"),
1054 _("turboing"),
1055 _("bad password"),
1056 _("username and password mismatch"),
1057 _("dual login detected"),
1061 rfds.clear();
1062 wfds.clear();
1063 efds.clear();
1065 msg = isconnecting() ? _("+ [icq] cannot connect") : _("+ [icq] disconnected");
1067 logger.putourstatus(icq, getstatus(), offline);
1069 clist.setoffline(icq);
1070 fonline = false;
1072 if(!reasons[ev->getReason()].empty()) {
1073 msg += ": ";
1074 msg += reasons[ev->getReason()];
1076 logger.putmessage((string) _("icq disconnection reason") + ": " +
1077 reasons[ev->getReason()]);
1079 if(ev->getReason() == DisconnectedEvent::FAILED_DUALLOGIN)
1080 manualstatus = offline;
1083 face.log(msg);
1084 face.update();
1087 static string fixicqrtf(string msg) {
1088 int pos, bpos, n;
1089 string sub;
1091 static char *emoticons[] = {
1092 ":-)", ":-O", ":-|", ":-\\", ":-(", ":-*", "8-/", ":~(",
1093 ";-)", ">:-O", ":`(", ":-X", ":-P", "B-)", "O:-)", ":-D",
1094 "*ANNOYED*", "*DISGUSTED*", "*DROOLING*", "*GIGGLING*",
1095 "*JOKINGLY*", "*SHOCKED*", "*WHINNING*", "*SURPRISED*",
1096 "*SURPRISED*", "*IN LOVE*"
1099 for(pos = 0; (pos = msg.find("<##icqimage", pos)) != -1; ) {
1100 if((bpos = msg.find(">", pos)) != -1) {
1101 sub = msg.substr(pos, bpos-pos);
1103 if(sub.size() > 2) sub.erase(0, sub.size()-2);
1104 n = hex2int(sub);
1106 if(n >= 0 && n <= 25) {
1107 msg.erase(pos, bpos-pos+1);
1108 msg.insert(pos, emoticons[n]);
1109 } else {
1110 pos++;
1115 return msg;
1118 void icqhook::messaged_cb(MessageEvent *ev) {
1119 imcontact ic;
1120 string text;
1122 ic = imcontact(ev->getContact()->getUIN(), icq);
1124 if(ev->getType() == MessageEvent::Normal) {
1125 NormalMessageEvent *r = static_cast<NormalMessageEvent *>(ev);
1127 bool converted = false;
1129 // check for UCS-2BE encoding in message
1130 if (r->getEncoding() == (unsigned int)0x0002) {
1131 string msg = r->getMessage();
1132 text = rusconv("ck", msg);
1133 converted = true;
1135 else
1136 text = r->getMessage();
1137 if(text.substr(0, 6) == "{\\rtf1")
1138 text = fixicqrtf(striprtf(text, converted?conf->getconvertto(proto):conf->getconvertfrom(proto)));
1140 text = converted ? text : rusconv("wk", text);
1142 #ifdef HAVE_GPGME
1143 const string pgpBlockBegin = "-----BEGIN PGP MESSAGE-----";
1144 const string pgpBlockEnd = "-----END PGP MESSAGE-----";
1145 string enc;
1146 int pgpDataBegin = text.find(pgpBlockBegin);
1147 int pgpDataEnd = text.find(pgpBlockEnd);
1149 // find where actual PGP data starts
1150 if (pgpDataBegin != string::npos) {
1151 int a = text.find("\n\n", pgpDataBegin+1);
1152 int b = text.find("\r\n\r\n", pgpDataBegin+1);
1154 if(a != string::npos) {
1155 if(b != string::npos) {
1156 // if we found both, take the smaller value
1157 if (a<b) {
1158 pgpDataBegin = a;
1159 } else {
1160 pgpDataBegin = b;
1162 } else {
1163 // we didn't find second match, so just take first
1164 pgpDataBegin = a;
1166 } else {
1167 // we didn't find first, so take whatever is in second
1168 pgpDataBegin = b;
1172 if((pgpDataBegin != string::npos) && (pgpDataEnd != string::npos)) {
1173 pgpDataBegin++;
1174 enc=text.substr(pgpDataBegin, pgpDataEnd-pgpDataBegin);
1176 icqcontact *c = clist.get(ic);
1178 if(c) {
1179 if(!enc.empty()) {
1180 c->setusepgpkey(true);
1181 if(pgp.enabled(proto)) {
1182 string dec = pgp.decrypt(enc, proto);
1183 string logMsg;
1185 if(dec.length() != 0) {
1186 logMsg="+ "+ic.totext()+" ("+c->getdispnick()+") PGP message decoded";
1187 text = dec;
1188 } else {
1189 // if we fail to decode message,
1190 // just display it as it is
1191 logMsg="+ "+ic.totext()+" ("+c->getdispnick()+") FAILED to decode PGP message";
1193 logger.putmessage(logMsg);
1194 face.log(logMsg);
1195 } else {
1196 c->setusepgpkey(false);
1198 } else {
1199 c->setusepgpkey(false);
1203 #endif
1205 em.store(immessage(ic, imevent::incoming, text, r->getTime()));
1207 } else if(ev->getType() == MessageEvent::URL) {
1208 URLMessageEvent *r = static_cast<URLMessageEvent *>(ev);
1209 em.store(imurl(ic, imevent::incoming,
1210 rusconv("wk", r->getURL()),
1211 rusconv("wk", r->getMessage())));
1213 } else if(ev->getType() == MessageEvent::SMS) {
1214 SMSMessageEvent *r = static_cast<SMSMessageEvent *>(ev);
1215 icqcontact *c = clist.getmobile(r->getSender());
1217 if(!c)
1218 if(c = clist.addnew(imcontact(0, infocard), true)) {
1219 icqcontact::basicinfo b = c->getbasicinfo();
1220 b.cellular = r->getSender();
1221 c->setbasicinfo(b);
1223 c->setdispnick(b.cellular);
1224 c->setnick(b.cellular);
1227 if(c) {
1228 em.store(imsms(c, imevent::incoming, rusconv("uk", r->getMessage())));
1231 } else if(ev->getType() == MessageEvent::AuthReq) {
1232 AuthReqEvent *r = static_cast<AuthReqEvent *>(ev);
1233 em.store(imauthorization(ic, imevent::incoming, imauthorization::Request,
1234 rusconv("wk", r->getMessage())));
1236 } else if(ev->getType() == MessageEvent::AuthAck) {
1237 AuthAckEvent *r = static_cast<AuthAckEvent *>(ev);
1238 icqcontact *c = clist.get(ic);
1240 if(c) {
1241 icqcontact::basicinfo bi = c->getbasicinfo();
1242 bi.authawait = false;
1243 c->setbasicinfo(bi);
1245 ContactRef cr = cli.getContactTree()[ic.uin];
1246 if(cr.get()) {
1247 cr->setAuthAwait(false);
1248 //cli.removeServerBasedContact(cr);
1249 //cli.uploadServerBasedContact(cr);
1253 if(r->isGranted()) {
1254 em.store(imnotification(ic, _("The user has accepted your authorization request")));
1256 } else {
1257 em.store(imnotification(ic, (string)
1258 _("The user has rejected your authorization request; the message was: ") + r->getMessage()));
1262 } else if(ev->getType() == MessageEvent::EmailEx) {
1263 EmailExEvent *r = static_cast<EmailExEvent *>(ev);
1264 processemailevent(r->getSender(), r->getEmail(), r->getMessage());
1266 } else if(ev->getType() == MessageEvent::WebPager) {
1267 WebPagerEvent *r = static_cast<WebPagerEvent *>(ev);
1268 processemailevent(r->getSender(), r->getEmail(), r->getMessage());
1270 } else if(ev->getType() == MessageEvent::UserAdd) {
1271 UserAddEvent *r = static_cast<UserAddEvent *>(ev);
1272 em.store(imnotification(ic,
1273 _("The user has added you to his/her contact list")));
1275 } else if(ev->getType() == MessageEvent::Contacts) {
1276 ContactMessageEvent *r = static_cast<ContactMessageEvent *>(ev);
1277 vector< pair<unsigned int, string> > lst;
1279 list<ContactRef> clst = r->getContacts();
1280 list<ContactRef>::iterator il;
1282 for(il = clst.begin(); il != clst.end(); ++il) {
1283 lst.push_back(make_pair((*il)->getUIN(), (*il)->getAlias()));
1286 em.store(imcontacts(ic, imevent::incoming, lst));
1290 ev->setDelivered(true);
1293 void icqhook::messageack_cb(MessageEvent *ev) {
1294 imcontact ic;
1295 icqcontact *c;
1296 ICQMessageEvent *me;
1298 ic = imcontact(ev->getContact()->getUIN(), icq);
1299 c = clist.get(ic);
1301 if(!c) {
1302 c = clist.get(contactroot);
1303 c->setdispnick(cli.getSelfContact()->getAlias());
1306 if(ev->isFinished()) {
1307 // The FINAL decision.
1309 switch(ev->getType()) {
1310 case MessageEvent::SMS:
1311 if(!ev->isDelivered()) {
1312 if(ev->getContact()->getUIN()) {
1313 face.log(_("+ [icq] failed SMS to %s, %s"),
1314 c->getdispnick().c_str(), ic.totext().c_str());
1315 } else {
1316 face.log(_("+ [icq] failed SMS to %s"),
1317 ev->getContact()->getAlias().c_str());
1320 break;
1322 case MessageEvent::AwayMessage:
1323 if(ev->isDelivered()) {
1324 AwayMessageEvent *r;
1326 if(r = dynamic_cast<AwayMessageEvent *>(ev)) {
1327 em.store(imnotification(ic, string() + _("Away message:") + "\n\n" +
1328 rusconv("wk", r->getAwayMessage())));
1330 } else {
1331 face.log(_("+ [icq] cannot fetch away msg from %s, %s (maybe no away msg set)"),
1332 c->getdispnick().c_str(), ic.totext().c_str());
1334 break;
1336 } else {
1339 * Rejected, but there is still something to be done.
1345 void icqhook::contactlist_cb(ContactListEvent *ev) {
1348 void icqhook::contact_status_change_signal_cb(StatusChangeEvent *ev) {
1349 icqcontact *c = clist.get(imcontact(ev->getUIN(), icq));
1351 if(c) {
1352 ContactRef ic = ev->getContact();
1353 StatusChangeEvent *tev = dynamic_cast<StatusChangeEvent*>(ev);
1354 imstatus nst = icq2imstatus(tev->getStatus());
1356 if(ic->isInvisible()) nst = invisible;
1358 c->setidlefor(ic->getExtPort());
1359 logger.putonline(c, c->getstatus(), nst);
1360 c->setstatus(nst);
1362 if (ic->get_signon_time())
1363 c->setonlinesince(ic->get_signon_time());
1365 if (nst == offline)
1366 c->setlasttyping(0);
1370 void icqhook::contact_userinfo_change_signal_cb(UserInfoChangeEvent *ev) {
1371 icqcontact *c = clist.get(imcontact(ev->getUIN(), icq));
1372 ContactRef ic = ev->getContact();
1374 if(!c) {
1375 c = clist.get(contactroot);
1378 * In case we wanna look up info about a user which
1379 * is not on our contact list.
1384 if(!ev->isTransientDetail()) {
1385 updateinforecord(ic, c);
1387 } else {
1388 char *p;
1389 string lastip, sbuf, oldip;
1390 struct in_addr addr;
1392 oldip = c->getlastip();
1393 addr.s_addr = ntohl(ic->getExtIP());
1394 if(p = inet_ntoa(addr)) lastip = p;
1396 if(lastip.find_first_not_of(".0") != -1) {
1397 addr.s_addr = ntohl(ic->getLanIP());
1398 if(p = inet_ntoa(addr)) {
1399 sbuf = p;
1401 if(sbuf.find_first_not_of(".0") != -1 && lastip != sbuf) {
1402 if(!lastip.empty()) lastip += " ";
1403 lastip += sbuf;
1407 c->setlastip(lastip);
1409 else
1411 if ((c->getstatus() != offline) && (oldip.find_first_of("*")))
1413 oldip.insert(0, "* ");
1414 c->setlastip(oldip);
1420 void icqhook::contact_typing_signal_cb(UserTypingNotificationEvent *ev) {
1421 icqcontact *c = clist.get(imcontact(ev->getUIN(), icq));
1422 if(c)
1424 time_t when = ev->isTyping() ? (time(NULL) + 300) : 0; // nobody should type for more than five minutes without a break...
1425 c->setlasttyping(when);
1426 face.relaxedupdate();
1430 void icqhook::newuin_cb(NewUINEvent *ev) {
1431 reguin = ev->getUIN();
1434 void icqhook::rate_cb(RateInfoChangeEvent *ev) {
1437 void icqhook::logger_cb(LogEvent *ev) {
1438 switch(ev->getType()) {
1439 case LogEvent::PACKET:
1440 case LogEvent::DIRECTPACKET:
1441 face.log(ev->getMessage());
1442 break;
1444 default:
1445 face.log(ev->getMessage());
1446 break;
1450 void icqhook::socket_cb(SocketEvent *ev) {
1451 vector<int>::iterator i;
1453 if(dynamic_cast<AddSocketHandleEvent*>(ev)) {
1454 AddSocketHandleEvent *cev = dynamic_cast<AddSocketHandleEvent*>(ev);
1456 if(cev->isRead()) rfds.push_back(cev->getSocketHandle());
1457 if(cev->isWrite()) wfds.push_back(cev->getSocketHandle());
1458 if(cev->isException()) efds.push_back(cev->getSocketHandle());
1460 } else if(dynamic_cast<RemoveSocketHandleEvent*>(ev)) {
1461 RemoveSocketHandleEvent *cev = dynamic_cast<RemoveSocketHandleEvent*>(ev);
1463 i = find(rfds.begin(), rfds.end(), cev->getSocketHandle());
1464 if(i != rfds.end())
1465 rfds.erase(i);
1467 i = find(wfds.begin(), wfds.end(), cev->getSocketHandle());
1468 if(i != wfds.end())
1469 wfds.erase(i);
1471 i = find(efds.begin(), efds.end(), cev->getSocketHandle());
1472 if(i != efds.end())
1473 efds.erase(i);
1477 void icqhook::want_auto_resp_cb(ICQMessageEvent *ev) {
1478 /* TODO: something should probably be logged here, but
1479 * logging an UNITIALIZED BUFFER seems pretty stupid to me
1481 /* char buf[128]; */
1483 string ident;
1484 imcontact cont = imcontact(ev->getSenderUIN(), icq);
1485 icqcontact *c = clist.get(cont);
1487 ident = cont.totext();
1488 if(c) ident += " (" + c->getdispnick() + ")";
1490 /* logger.putmessage(buf); */
1491 ev->setAwayMessage(rusconv("kw", conf->getawaymsg(icq)));
1494 void icqhook::search_result_cb(SearchResultEvent *ev) {
1495 if(ev == searchevent) {
1496 ContactRef cont = ev->getLastContactAdded();
1498 if(searchdest && cont.get()) {
1499 icqcontact *c = new icqcontact(imcontact(cont->getUIN(), icq));
1500 icqcontact::basicinfo binfo = c->getbasicinfo();
1502 if(ev->getSearchType() == SearchResultEvent::RandomChat) {
1503 binfo.fname = _("Random Chat User");
1505 } else {
1506 c->setnick(rusconv("wk", cont->getAlias()));
1507 c->setdispnick(c->getnick());
1509 binfo.fname = rusconv("wk", cont->getFirstName());
1510 binfo.lname = rusconv("wk", cont->getLastName());
1511 binfo.email = rusconv("wk", cont->getEmail());
1515 string line = (cont->getStatus() == STATUS_ONLINE ? "o " : " ") + c->getnick();
1517 if(line.size() > 12) line.resize(12);
1518 else line += string(12-line.size(), ' ');
1520 line += " " + binfo.fname + " " + binfo.lname;
1521 if(!binfo.email.empty()) line += " <" + binfo.email + ">";
1523 binfo.requiresauth = cont->getAuthReq();
1524 binfo.authawait = cont->getAuthAwait();
1526 c->setbasicinfo(binfo);
1528 foundguys.push_back(c);
1529 searchdest->additem(conf->getcolor(cp_clist_icq), c, line);
1530 searchdest->redraw();
1533 if(ev->isFinished() && searchdest) {
1534 face.findready();
1535 log(logSearchFinished, ev->getContactList().size());
1536 searchdest = 0;
1541 void icqhook::self_contact_userinfo_change_cb(UserInfoChangeEvent *ev) {
1542 if(!ev->isTransientDetail()) {
1543 icqcontact *c = clist.get(contactroot);
1545 updateinforecord(cli.getSelfContact(), c);
1546 updateinforecord(cli.getSelfContact(), clist.get(imcontact(cli.getUIN(), icq)));
1550 * Fill in the locally stored parts now.
1554 icqconf::imaccount im = conf->getourid(icq);
1555 icqcontact::basicinfo cbinfo = c->getbasicinfo();
1556 cbinfo.webaware = im.additional["webaware"] == "1";
1557 cbinfo.randomgroup = strtoul(im.additional["randomgroup"].c_str(), 0, 0);
1558 c->setbasicinfo(cbinfo);
1562 void icqhook::self_contact_status_change_cb(StatusChangeEvent *ev) {
1563 face.update();
1568 void icqhook::password_changed_cb(PasswordChangeEvent *ev) {
1569 if(ev->isSuccess()) {
1570 icqconf::imaccount acc = conf->getourid(icq);
1571 acc.password = ev->getPassword();
1572 conf->setourid(acc);
1573 log(logPasswordChanged);
1579 void icqhook::sbl_received_cb(SBLReceivedEvent *ev) {
1580 icqcontact *cc;
1581 ContactTree &tree = cli.getContactTree();
1582 ContactTree::iterator curr = ev->tree.begin();
1584 sblrecv = false;
1586 while(curr != ev->tree.end()) {
1587 ContactTree::Group *lg = 0;
1589 ContactTree::iterator igl = tree.begin();
1590 while(igl != tree.end()) {
1591 if((*igl).get_label() == (*curr).get_label()) {
1592 lg = &(*igl);
1593 break;
1595 ++igl;
1598 if(!lg) {
1599 lg = &(tree.add_group((*curr).get_label(), (*curr).get_id()));
1600 } else {
1601 lg->set_id((*curr).get_id());
1604 ContactTree::Group::iterator ig = curr->begin();
1605 while(ig != curr->end()) {
1606 imcontact ic((*ig)->getUIN(), proto);
1607 clist.updateEntry(ic, (*curr).get_label());
1609 ContactRef nc = tree[ic.uin];
1610 if(nc.get()) {
1611 ContactTree::Group &cg = tree.lookup_group_containing_contact(nc);
1612 tree.relocate_contact(nc, cg, *lg);
1613 } else {
1614 nc = lg->add(new Contact(ic.uin));
1616 nc->setAuthAwait((*ig)->getAuthAwait());
1618 if(cc = clist.get(ic)) {
1619 icqcontact::basicinfo bi = cc->getbasicinfo();
1620 bi.authawait = nc->getAuthAwait();
1621 bi.serverbased = true;
1622 cc->setbasicinfo(bi);
1625 nc->setServerBased(true);
1626 nc->setServerSideInfo((*ig)->getServerSideGroupID(), (*ig)->getServerSideID());
1628 ++ig;
1630 ++curr;
1633 sblrecv = true;
1636 ContactRef icqhook::addContact(unsigned int uin, const string &groupname) {
1637 ContactTree& ct = cli.getContactTree();
1638 ContactTree::Group *gp = 0;
1640 ContactTree::iterator curr = ct.begin();
1641 while(curr != ct.end()) {
1642 if((*curr).get_label() == groupname) {
1643 gp = &(*curr);
1644 break;
1646 ++curr;
1649 if(!gp) gp = &(ct.add_group(groupname));
1651 ContactRef cont(new Contact(uin));
1652 gp->add(cont);
1654 return cont;
1657 #endif /* BUILD_ICQ */