1 /*
2 *
3 * centerim MSN protocol handling class
4 * $Id: msnhook.cc,v 1.91 2005/02/03 02:02:37 konst Exp $
5 *
6 * Copyright (C) 2001-2004 by Konstantin Klyagin <k@thekonst.net>
7 *
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.
12 *
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.
17 *
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
22 *
23 */
24
25 #include "icqcommon.h"
26
27 #ifdef BUILD_MSN
28
29 #include "msnhook.h"
30 #include "icqconf.h"
31 #include "icqface.h"
32 #include "icqcontacts.h"
33 #include "accountmanager.h"
34 #include "eventmanager.h"
35 #include "imlogger.h"
36 #include "connwrap.h"
37 #include "icqgroups.h"
38
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netdb.h>
44 #include <arpa/inet.h>
45
46 msnhook mhook;
47
nicknormalize(const string & nick)48 static string nicknormalize(const string &nick) {
49 if(nick.find("@") == -1) return nick + "@hotmail.com";
50 return nick;
51 }
52
nicktodisp(const string & nick)53 static string nicktodisp(const string &nick) {
54 int pos;
55 string r = nick;
56
57 if((pos = r.find("@")) != -1)
58 if(r.substr(pos+1) == "hotmail.com")
59 r.erase(pos);
60
61 return r;
62 }
63
64 static map<MSN::BuddyStatus, imstatus> convstat;
65
buddy2stat(MSN::BuddyStatus bst)66 static imstatus buddy2stat(MSN::BuddyStatus bst) {
67 map<MSN::BuddyStatus, imstatus>::const_iterator i = convstat.find(bst);
68 if(i != convstat.end())
69 return i->second;
70
71 return offline;
72 }
73
stat2buddy(imstatus st)74 static MSN::BuddyStatus stat2buddy(imstatus st) {
75 map<MSN::BuddyStatus, imstatus>::const_iterator i = convstat.begin();
76 while(i != convstat.end()) {
77 if(st == i->second)
78 return i->first;
79 ++i;
80 }
81
82 return MSN::STATUS_AVAILABLE;
83 }
84
85 // ----------------------------------------------------------------------------
86
msnhook()87 msnhook::msnhook(): abstracthook(msn), conn(cb) {
88 ourstatus = offline;
89 fonline = false;
90 destroying = false;
91
92 fcapabs.insert(hookcapab::changedetails);
93 fcapabs.insert(hookcapab::directadd);
94 }
95
~msnhook()96 msnhook::~msnhook() {
97 if(conn.connectionState() != MSN::NotificationServerConnection::NS_DISCONNECTED) {
98 destroying = true;
99 conn.disconnect();
100 }
101 }
102
init()103 void msnhook::init() {
104 manualstatus = conf->getstatus(msn);
105
106 convstat[MSN::STATUS_AVAILABLE] = available;
107 convstat[MSN::STATUS_INVISIBLE] = invisible;
108 convstat[MSN::STATUS_BUSY] = dontdisturb;
109 convstat[MSN::STATUS_ONTHEPHONE] = occupied;
110 convstat[MSN::STATUS_AWAY] = notavail;
111 convstat[MSN::STATUS_BERIGHTBACK] = away;
112 convstat[MSN::STATUS_OUTTOLUNCH] = outforlunch;
113 convstat[MSN::STATUS_IDLE] = away;
114 }
115
connect()116 void msnhook::connect() {
117 icqconf::imaccount account = conf->getourid(msn);
118
119 log(logConnecting);
120
121 readinfo = flogged = false;
122 fonline = true;
123
124 try {
125 if(conn.connectionState() != MSN::NotificationServerConnection::NS_DISCONNECTED)
126 conn.disconnect();
127
128 rfds.clear();
129 wfds.clear();
130
131 conn.connect(account.server, account.port, nicknormalize(account.nickname), account.password);
132 } catch(...) {
133 }
134 }
135
disconnect()136 void msnhook::disconnect() {
137 fonline = false;
138 if(conn.connectionState() != MSN::NotificationServerConnection::NS_DISCONNECTED)
139 conn.disconnect();
140 clist.setoffline(mhook.proto);
141 log(logDisconnected);
142 }
143
exectimers()144 void msnhook::exectimers() {
145 if(logged()) {
146 if(timer_current-timer_ping > conn.nextPing()) {
147 try {
148 conn.sendPing();
149 timer_ping = timer_current;
150 } catch(...) {
151 }
152 }
153 }
154 }
155
main()156 void msnhook::main() {
157 vector<int>::const_iterator i;
158 fd_set rs, ws, es;
159 struct timeval tv;
160 int hsock = 0;
161 MSN::Connection *c;
162
163 FD_ZERO(&rs);
164 FD_ZERO(&ws);
165 FD_ZERO(&es);
166
167 getsockets(rs, ws, es, hsock);
168 tv.tv_sec = tv.tv_usec = 0;
169
170 try {
171 if(select(hsock+1, &rs, &ws, &es, &tv) > 0) {
172 for(i = rfds.begin(); i != rfds.end(); ++i)
173 if(FD_ISSET(*i, &rs)) {
174 c = conn.connectionWithSocket(*i);
175 if(c) c->dataArrivedOnSocket();
176 return;
177 }
178
179 for(i = wfds.begin(); i != wfds.end(); ++i)
180 if(FD_ISSET(*i, &ws)) {
181 c = conn.connectionWithSocket(*i);
182
183 if(c) {
184 if(!c->isConnected()) {
185 c->socketConnectionCompleted();
186 } else {
187 c->socketIsWritable();
188 }
189 }
190
191 return;
192 }
193 }
194 } catch(...) {
195 }
196 }
197
getsockets(fd_set & rf,fd_set & wf,fd_set & efds,int & hsocket) const198 void msnhook::getsockets(fd_set &rf, fd_set &wf, fd_set &efds, int &hsocket) const {
199 vector<int>::const_iterator i;
200
201 for(i = rfds.begin(); i != rfds.end(); ++i) {
202 hsocket = max(hsocket, *i);
203 FD_SET(*i, &rf);
204 }
205
206 for(i = wfds.begin(); i != wfds.end(); ++i) {
207 hsocket = max(hsocket, *i);
208 FD_SET(*i, &wf);
209 }
210 }
211
isoursocket(fd_set & rf,fd_set & wf,fd_set & efds) const212 bool msnhook::isoursocket(fd_set &rf, fd_set &wf, fd_set &efds) const {
213 vector<int>::const_iterator i;
214
215 for(i = rfds.begin(); i != rfds.end(); ++i)
216 if(FD_ISSET(*i, &rf))
217 return true;
218
219 for(i = wfds.begin(); i != wfds.end(); ++i)
220 if(FD_ISSET(*i, &wf))
221 return true;
222
223 return false;
224 }
225
online() const226 bool msnhook::online() const {
227 return fonline;
228 }
229
logged() const230 bool msnhook::logged() const {
231 return fonline && flogged;
232 }
233
isconnecting() const234 bool msnhook::isconnecting() const {
235 return fonline && !flogged;
236 }
237
enabled() const238 bool msnhook::enabled() const {
239 return true;
240 }
241
send(const imevent & ev)242 bool msnhook::send(const imevent &ev) {
243 string text;
244 string rcpt = nicknormalize(ev.getcontact().nickname);
245
246 if(ev.gettype() == imevent::message) {
247 const immessage *m = static_cast<const immessage *>(&ev);
248 if(m) text = m->gettext();
249
250 } else if(ev.gettype() == imevent::url) {
251 const imurl *m = static_cast<const imurl *>(&ev);
252 if(m) text = m->geturl() + "\n\n" + m->getdescription();
253
254 } else if(ev.gettype() == imevent::file) {
255 const imfile *m = static_cast<const imfile *>(&ev);
256 vector<imfile::record> files = m->getfiles();
257 vector<imfile::record>::const_iterator ir;
258
259 for(ir = files.begin(); ir != files.end(); ++ir) {
260 imfile::record r;
261
262 r.fname = ir->fname;
263 r.size = ir->size;
264
265 imfile fr(ev.getcontact(), imevent::outgoing, "", vector<imfile::record>(1, r));
266
267 try {
268 qevent *ctx = new qevent(qevent::qeFile, rcpt, ir->fname);
269
270 if(lconn.find(rcpt) != lconn.end()) sendmsn(lconn[rcpt], ctx);
271 else conn.requestSwitchboardConnection(ctx);
272
273 } catch(...) {
274 }
275 }
276
277 return true;
278 }
279
280 icqcontact *c = clist.get(ev.getcontact());
281 text = rusconv("ku", text);
282
283 if(c)
284 if(c->getstatus() != offline || !c->inlist()) {
285 try {
286 qevent *ctx = new qevent(qevent::qeMsg, rcpt, text);
287
288 if(lconn.find(rcpt) != lconn.end()) sendmsn(lconn[rcpt], ctx);
289 else conn.requestSwitchboardConnection(ctx);
290
291 } catch(...) {
292 }
293
294 return true;
295 }
296
297 return false;
298 }
299
findgroup(const imcontact & ic,string & gname) const300 int msnhook::findgroup(const imcontact &ic, string &gname) const {
301 int gid = -1;
302 icqcontact *c;
303
304 if(c = clist.get(ic)) {
305 vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), c->getgroupid());
306 if(ig != groups.end()) {
307 gname = ig->getname();
308 map<int, string>::const_iterator im = mgroups.begin();
309 while(im != mgroups.end() && gid == -1) {
310 if(im->second == ig->getname())
311 gid = im->first;
312 ++im;
313 }
314 }
315 }
316
317 return gid;
318 }
319
sendnewuser(const imcontact & ic)320 void msnhook::sendnewuser(const imcontact &ic) {
321 if(logged() && !readinfo) {
322 icqcontact *c;
323 imcontact icc(nicktodisp(ic.nickname), msn);
324
325 if(icc.nickname != ic.nickname)
326 if(c = clist.get(ic)) {
327 c->setdesc(icc);
328 c->setnick(icc.nickname);
329 c->setdispnick(icc.nickname);
330 }
331
332 int gid;
333 string gname;
334
335 gid = findgroup(ic, gname);
336
337 try {
338 if(gid == -1) {
339 gid = 0;
340 }
341 conn.addToGroup(nicknormalize(ic.nickname), gid);
342 } catch(...) {
343 }
344 }
345
346 requestinfo(ic);
347 }
348
setautostatus(imstatus st)349 void msnhook::setautostatus(imstatus st) {
350 if(st != offline) {
351 if(!logged()) {
352 connect();
353 } else {
354 logger.putourstatus(msn, ourstatus, st);
355 try {
356 conn.setState(stat2buddy(ourstatus = st));
357 } catch(...) {
358 }
359 }
360 } else {
361 if(getstatus() != offline) {
362 disconnect();
363 }
364 }
365 }
366
getstatus() const367 imstatus msnhook::getstatus() const {
368 return online() ? ourstatus : offline;
369 }
370
removeuser(const imcontact & ic)371 void msnhook::removeuser(const imcontact &ic) {
372 removeuser(ic, true);
373 }
374
removeuser(const imcontact & ic,bool report)375 void msnhook::removeuser(const imcontact &ic, bool report) {
376 int i;
377 bool found;
378 vector<msnbuddy>::const_iterator ib = find(slst["FL"].begin(), slst["FL"].end(), nicknormalize(ic.nickname));
379
380 if(online() && ib != slst["FL"].end()) {
381 if(report)
382 log(logContactRemove, ic.nickname.c_str());
383
384 try {
385 conn.removeFromGroup(nicknormalize(ic.nickname), ib->gid);
386
387 for(i = 0, found = false; i < clist.count && !found; i++) {
388 icqcontact *c = (icqcontact *) clist.at(i);
389 found = c->getdesc().pname == msn
390 && groups.getname(c->getgroupid()) == mgroups[ib->gid];
391 }
392
393 if(!found && ib->gid > 0)
394 conn.removeGroup(ib->gid);
395 } catch(...) {
396 }
397 }
398 }
399
requestinfo(const imcontact & ic)400 void msnhook::requestinfo(const imcontact &ic) {
401 icqcontact *c = clist.get(ic);
402 if(!c) c = clist.get(contactroot);
403
404 icqcontact::moreinfo m = c->getmoreinfo();
405 icqcontact::basicinfo b = c->getbasicinfo();
406
407 b.email = nicknormalize(ic.nickname);
408 m.homepage = "http://members.msn.com/" + b.email;
409
410 if(ic.nickname == conf->getourid(msn).nickname)
411 c->setnick(friendlynicks[ic.nickname]);
412
413 c->setmoreinfo(m);
414 c->setbasicinfo(b);
415 }
416
lookup(const imsearchparams & params,verticalmenu & dest)417 void msnhook::lookup(const imsearchparams ¶ms, verticalmenu &dest) {
418 if(params.reverse) {
419 vector<msnbuddy>::const_iterator i = slst["RL"].begin();
420
421 while(i != slst["RL"].end()) {
422 icqcontact *c = new icqcontact(imcontact(nicktodisp(i->nick), msn));
423 c->setnick(i->friendly);
424
425 dest.additem(conf->getcolor(cp_clist_msn), c, (string) " " + i->nick);
426 ++i;
427 }
428 face.findready();
429
430 face.log(_("+ [msn] reverse users listing finished, %d found"),
431 slst["RL"].size());
432
433 dest.redraw();
434 }
435 }
436
getneedsync()437 vector<icqcontact *> msnhook::getneedsync() {
438 int i;
439 vector<icqcontact *> r;
440 bool found;
441
442 for(i = 0; i < clist.count; i++) {
443 icqcontact *c = (icqcontact *) clist.at(i);
444
445 if(c->getdesc().pname == msn) {
446 vector<msnbuddy>::const_iterator fi = slst["FL"].begin();
447
448 for(found = false; fi != slst["FL"].end() && !found; ++fi)
449 found = c->getdesc().nickname == fi->nick;
450
451 if(!found)
452 r.push_back(c);
453 }
454 }
455
456 return r;
457 }
458
sendupdateuserinfo(const icqcontact & c)459 void msnhook::sendupdateuserinfo(const icqcontact &c) {
460 try {
461 conn.setFriendlyName(c.getnick());
462 } catch(...) {
463 }
464 }
465
checkfriendly(icqcontact * c,const string friendlynick,bool forcefetch)466 void msnhook::checkfriendly(icqcontact *c, const string friendlynick, bool forcefetch) {
467 string oldnick = c->getnick();
468 string newnick = unmime(friendlynick);
469
470 c->setnick(newnick);
471
472 if(forcefetch || (oldnick != newnick && c->getdispnick() == oldnick) || oldnick.empty()) {
473 c->setdispnick(newnick);
474 face.relaxedupdate();
475 }
476 }
477
checkinlist(imcontact ic)478 void msnhook::checkinlist(imcontact ic) {
479 icqcontact *c = clist.get(ic);
480 vector<icqcontact *> notremote = getneedsync();
481
482 if(c)
483 if(c->inlist())
484 if(find(notremote.begin(), notremote.end(), c) != notremote.end())
485 mhook.sendnewuser(ic);
486 }
487
knowntransfer(const imfile & fr) const488 bool msnhook::knowntransfer(const imfile &fr) const {
489 return transferinfo.find(fr) != transferinfo.end();
490 }
491
replytransfer(const imfile & fr,bool accept,const string & localpath)492 void msnhook::replytransfer(const imfile &fr, bool accept, const string &localpath) {
493 if(accept) {
494 transferinfo[fr].second = localpath;
495
496 if(transferinfo[fr].second.substr(transferinfo[fr].second.size()-1) != "/")
497 transferinfo[fr].second += "/";
498
499 transferinfo[fr].second += justfname(fr.getfiles().begin()->fname);
500 // msn_filetrans_accept(transferinfo[fr].first, transferinfo[fr].second.c_str());
501
502 } else {
503 // msn_filetrans_reject(transferinfo[fr].first);
504 transferinfo.erase(fr);
505
506 }
507 }
508
aborttransfer(const imfile & fr)509 void msnhook::aborttransfer(const imfile &fr) {
510 // msn_filetrans_reject(transferinfo[fr].first);
511
512 face.transferupdate(fr.getfiles().begin()->fname, fr,
513 icqface::tsCancel, 0, 0);
514
515 transferinfo.erase(fr);
516 }
517
getfevent(MSN::FileTransferInvitation * fhandle,imfile & fr)518 bool msnhook::getfevent(MSN::FileTransferInvitation *fhandle, imfile &fr) {
519 map<imfile, pair<MSN::FileTransferInvitation *, string> >::const_iterator i = transferinfo.begin();
520
521 while(i != transferinfo.end()) {
522 if(i->second.first == fhandle) {
523 fr = i->first;
524 return true;
525 }
526 ++i;
527 }
528
529 return false;
530 }
531
updatecontact(icqcontact * c)532 void msnhook::updatecontact(icqcontact *c) {
533 string gname, nick = nicknormalize(c->getdesc().nickname);
534 vector<msnbuddy>::const_iterator ib = find(slst["FL"].begin(), slst["FL"].end(), nick);
535
536 if(ib != slst["FL"].end() && logged() && conf->getgroupmode() != icqconf::nogroups)
537 if(mhook.findgroup(c->getdesc(), gname) != ib->gid) {
538 try {
539 conn.removeFromList("FL", nick.c_str());
540 } catch(...) {
541 }
542
543 sendnewuser(c->getdesc());
544 }
545 }
546
renamegroup(const string & oldname,const string & newname)547 void msnhook::renamegroup(const string &oldname, const string &newname) {
548 if(logged()) {
549 map<int, string>::const_iterator im = mgroups.begin();
550 while(im != mgroups.end()) {
551 if(im->second == oldname) {
552 try {
553 conn.renameGroup(im->first, newname);
554 } catch(...) {
555 }
556
557 break;
558 }
559 ++im;
560 }
561 }
562 }
563
564 // ----------------------------------------------------------------------------
565
statusupdate(string buddy,string friendlyname,imstatus status)566 void msnhook::statusupdate(string buddy, string friendlyname, imstatus status) {
567 imcontact ic(nicktodisp(buddy), msn);
568 icqcontact *c = clist.get(ic);
569 bool forcefetch;
570
571 if(forcefetch = !c)
572 c = clist.addnew(ic, false);
573
574 if(!friendlyname.empty())
575 checkfriendly(c, friendlyname, forcefetch);
576
577 logger.putonline(ic, c->getstatus(), status);
578 c->setstatus(status);
579 }
580
581 // ----------------------------------------------------------------------------
582
sendmsn(MSN::SwitchboardServerConnection * conn,const qevent * ctx)583 void msnhook::sendmsn(MSN::SwitchboardServerConnection *conn, const qevent *ctx) {
584 MSN::FileTransferInvitation *inv;
585
586 switch(ctx->type) {
587 case msnhook::qevent::qeMsg:
588 conn->sendMessage(ctx->text);
589 break;
590
591 case msnhook::qevent::qeFile:
592 inv = conn->sendFile(ctx->text);
593 // if(inv) mhook.transferinfo[] = inv;
594 break;
595 }
596
597 delete ctx;
598 }
599
600 // ----------------------------------------------------------------------------
601
log(const string & s)602 static void log(const string &s) {
603 if(conf->getdebug())
604 face.log(s);
605 }
606
log(int writing,const char * buf)607 void msncallbacks::log(int writing, const char* buf) {
608 string pref = writing ? "OUT" : "IN";
609 ::log((string) "[" + pref + "] " + buf);
610 }
611
registerSocket(int s,int reading,int writing)612 void msncallbacks::registerSocket(int s, int reading, int writing) {
613 ::log("msncallbacks::registerSocket");
614 if(reading) mhook.rfds.push_back(s);
615 if(writing) mhook.wfds.push_back(s);
616 }
617
unregisterSocket(int s)618 void msncallbacks::unregisterSocket(int s) {
619 ::log("msncallbacks::unregisterSocket");
620 vector<int>::iterator i;
621
622 i = find(mhook.rfds.begin(), mhook.rfds.end(), s);
623 if(i != mhook.rfds.end()) mhook.rfds.erase(i);
624
625 i = find(mhook.wfds.begin(), mhook.wfds.end(), s);
626 if(i != mhook.wfds.end()) mhook.wfds.erase(i);
627 }
628
gotFriendlyName(MSN::Connection * conn,string friendlyname)629 void msncallbacks::gotFriendlyName(MSN::Connection * conn, string friendlyname) {
630 ::log("msncallbacks::gotFriendlyName");
631 if(!friendlyname.empty())
632 mhook.friendlynicks[conf->getourid(msn).nickname] = friendlyname;
633 }
634
gotBuddyListInfo(MSN::NotificationServerConnection * conn,MSN::ListSyncInfo * data)635 void msncallbacks::gotBuddyListInfo(MSN::NotificationServerConnection * conn, MSN::ListSyncInfo * data) {
636 ::log("msncallbacks::gotBuddyListInfo");
637 imcontact ic;
638 bool found;
639
640 mhook.readinfo = true;
641
642 std::map<int, MSN::Group>::iterator ig;
643
644 for(ig = data->groups.begin(); ig != data->groups.end(); ig++) {
645 mhook.mgroups[ig->second.groupID] = ig->second.name;
646 }
647
648 std::list<MSN::Buddy> &lst = data->forwardList;
649 std::list<MSN::Buddy>::iterator i;
650
651 for(i = lst.begin(); i != lst.end(); i++) {
652 int gid = 0;
653 if(!i->groups.empty()) gid = (*i->groups.begin())->groupID;
654 mhook.slst["FL"].push_back(msnbuddy(i->userName, i->friendlyName, gid));
655
656 ic = imcontact(nicktodisp(i->userName), msn);
657 icqcontact *c = clist.get(ic);
658 if(!c) c = clist.addnew(ic, false);
659
660 icqcontact::basicinfo bi = c->getbasicinfo();
661 icqcontact::workinfo wi = c->getworkinfo();
662
663 list<MSN::Buddy::PhoneNumber>::iterator ip = i->phoneNumbers.begin();
664 for(; ip != i->phoneNumbers.end(); ip++) {
665 if(ip->title == "PHH") bi.phone = ip->number; else
666 if(ip->title == "PHW") wi.phone = ip->number; else
667 if(ip->title == "PHM") bi.cellular = ip->number;
668 }
669
670 c->setbasicinfo(bi);
671 c->setworkinfo(wi);
672
673 for(found = false, ig = data->groups.begin(); ig != data->groups.end() && !found; ++ig) {
674 found = ig->second.groupID == gid;
675 if(found) clist.updateEntry(ic, ig->second.name);
676 }
677 }
678
679 for(lst = data->reverseList, i = lst.begin(); i != lst.end(); ++i)
680 mhook.slst["RL"].push_back(msnbuddy(i->userName, i->friendlyName));
681
682 mhook.readinfo = false;
683 mhook.flogged = true;
684
685 mhook.setautostatus(mhook.manualstatus);
686 mhook.timer_ping = timer_current;
687 mhook.log(abstracthook::logLogged);
688 face.update();
689 }
690
gotLatestListSerial(MSN::Connection * conn,int serial)691 void msncallbacks::gotLatestListSerial(MSN::Connection * conn, int serial) {
692 ::log("msncallbacks::gotLatestListSerial");
693 }
694
gotGTC(MSN::Connection * conn,char c)695 void msncallbacks::gotGTC(MSN::Connection * conn, char c) {
696 ::log("msncallbacks::gotGTC");
697 }
698
gotBLP(MSN::Connection * conn,char c)699 void msncallbacks::gotBLP(MSN::Connection * conn, char c) {
700 ::log("msncallbacks::gotBLP");
701 }
702
gotNewReverseListEntry(MSN::Connection * conn,MSN::Passport buddy,std::string friendlyname)703 void msncallbacks::gotNewReverseListEntry(MSN::Connection * conn, MSN::Passport buddy, std::string friendlyname) {
704 ::log("msncallbacks::gotNewReverseListEntry");
705
706 try {
707 mhook.conn.addToList("AL", buddy);
708 } catch(...) {
709 }
710
711 imcontact ic(nicktodisp(buddy), msn);
712 mhook.checkinlist(ic);
713 em.store(imnotification(ic, _("The user has added you to his/her contact list")));
714 }
715
addedListEntry(MSN::Connection * conn,string lst,MSN::Passport buddy,int groupID)716 void msncallbacks::addedListEntry(MSN::Connection * conn, string lst, MSN::Passport buddy, int groupID) {
717 ::log("msncallbacks::addedListEntry");
718 mhook.slst[lst].push_back(msnbuddy(buddy, "", groupID));
719 }
720
removedListEntry(MSN::Connection * conn,string lst,MSN::Passport buddy,int groupID)721 void msncallbacks::removedListEntry(MSN::Connection * conn, string lst, MSN::Passport buddy, int groupID) {
722 ::log("msncallbacks::removedListEntry");
723 vector<msnbuddy>::iterator i = mhook.slst[lst].begin();
724 while(i != mhook.slst[lst].end()) {
725 if(i->nick == buddy) {
726 mhook.slst[lst].erase(i);
727 i = mhook.slst[lst].begin();
728 } else {
729 ++i;
730 }
731 }
732 }
733
showError(MSN::Connection * conn,string msg)734 void msncallbacks::showError(MSN::Connection * conn, string msg) {
735 ::log(msg);
736 }
737
buddyChangedStatus(MSN::Connection * conn,MSN::Passport buddy,string friendlyname,MSN::BuddyStatus state)738 void msncallbacks::buddyChangedStatus(MSN::Connection * conn, MSN::Passport buddy, string friendlyname, MSN::BuddyStatus state) {
739 ::log("msncallbacks::buddyChangedStatus");
740 mhook.statusupdate(buddy, friendlyname, buddy2stat(state));
741 }
742
buddyOffline(MSN::Connection * conn,MSN::Passport buddy)743 void msncallbacks::buddyOffline(MSN::Connection * conn, MSN::Passport buddy) {
744 ::log("msncallbacks::buddyOffline");
745 mhook.statusupdate(buddy, "", offline);
746 }
747
gotSwitchboard(MSN::SwitchboardServerConnection * conn,const void * tag)748 void msncallbacks::gotSwitchboard(MSN::SwitchboardServerConnection * conn, const void * tag) {
749 ::log("msncallbacks::gotSwitchboard");
750
751 if(tag) {
752 const msnhook::qevent *ctx = static_cast<const msnhook::qevent *>(tag);
753 conn->inviteUser(ctx->nick);
754 }
755 }
756
buddyJoinedConversation(MSN::SwitchboardServerConnection * conn,MSN::Passport buddy,std::string friendlyname,int is_initial)757 void msncallbacks::buddyJoinedConversation(MSN::SwitchboardServerConnection * conn, MSN::Passport buddy, std::string friendlyname, int is_initial) {
758 ::log("msncallbacks::buddyJoinedConversation");
759 if(conn->auth.tag) {
760 const msnhook::qevent *ctx = static_cast<const msnhook::qevent *>(conn->auth.tag);
761 mhook.lconn[ctx->nick] = conn;
762 mhook.sendmsn(conn, ctx);
763 conn->auth.tag = 0;
764 }
765 }
766
buddyLeftConversation(MSN::SwitchboardServerConnection * conn,MSN::Passport buddy)767 void msncallbacks::buddyLeftConversation(MSN::SwitchboardServerConnection * conn, MSN::Passport buddy) {
768 ::log("msncallbacks::buddyLeftConversation");
769 }
770
gotInstantMessage(MSN::SwitchboardServerConnection * conn,MSN::Passport buddy,std::string friendlyname,MSN::Message * msg)771 void msncallbacks::gotInstantMessage(MSN::SwitchboardServerConnection * conn, MSN::Passport buddy, std::string friendlyname, MSN::Message * msg) {
772 ::log("msncallbacks::gotInstantMessage");
773 imcontact ic(nicktodisp(buddy), msn);
774
775 mhook.checkinlist(ic);
776
777 string text = mhook.rusconv("uk", msg->getBody());
778 em.store(immessage(ic, imevent::incoming, text));
779 }
780
failedSendingMessage(MSN::Connection * conn)781 void msncallbacks::failedSendingMessage(MSN::Connection * conn) {
782 ::log("msncallbacks::failedSendingMessage");
783 }
784
buddyTyping(MSN::Connection * conn,MSN::Passport buddy,std::string friendlyname)785 void msncallbacks::buddyTyping(MSN::Connection * conn, MSN::Passport buddy, std::string friendlyname) {
786 ::log("msncallbacks::buddyTyping");
787 icqcontact *c = clist.get(imcontact(nicktodisp(buddy), msn));
788 if(c) c->setlasttyping(timer_current);
789 }
790
gotInitialEmailNotification(MSN::Connection * conn,int unread_inbox,int unread_folders)791 void msncallbacks::gotInitialEmailNotification(MSN::Connection * conn, int unread_inbox, int unread_folders) {
792 ::log("msncallbacks::gotInitialEmailNotification");
793 face.log(_("+ [msn] unread e-mail: %d in inbox, %d in folders"),
794 unread_inbox, unread_folders);
795 }
796
gotNewEmailNotification(MSN::Connection * conn,string from,string subject)797 void msncallbacks::gotNewEmailNotification(MSN::Connection * conn, string from, string subject) {
798 ::log("msncallbacks::gotNewEmailNotification");
799 face.log(_("+ [msn] e-mail from %s, %s"), from.c_str(), subject.c_str());
800 clist.get(contactroot)->playsound(imevent::email);
801 }
802
gotFileTransferInvitation(MSN::Connection * conn,MSN::Passport buddy,std::string friendlyname,MSN::FileTransferInvitation * inv)803 void msncallbacks::gotFileTransferInvitation(MSN::Connection * conn, MSN::Passport buddy, std::string friendlyname, MSN::FileTransferInvitation * inv) {
804 ::log("msncallbacks::gotFileTransferInvitation");
805 if(!mhook.fcapabs.count(hookcapab::files))
806 return;
807
808 imfile::record r;
809 r.fname = inv->fileName;
810 r.size = inv->fileSize;
811
812 imcontact ic(nicktodisp(buddy), msn);
813 mhook.checkinlist(ic);
814
815 imfile fr(ic, imevent::incoming, "", vector<imfile::record>(1, r));
816
817 mhook.transferinfo[fr].first = inv;
818 em.store(fr);
819
820 face.transferupdate(inv->fileName, fr, icqface::tsInit, inv->fileSize, 0);
821 }
822
fileTransferProgress(MSN::FileTransferInvitation * inv,string status,unsigned long recv,unsigned long total)823 void msncallbacks::fileTransferProgress(MSN::FileTransferInvitation * inv, string status, unsigned long recv, unsigned long total) {
824 ::log("msncallbacks::fileTransferProgress");
825 imfile fr;
826
827 if(mhook.getfevent(inv, fr)) {
828 face.transferupdate(fr.getfiles().begin()->fname, fr,
829 icqface::tsProgress, total, recv);
830 }
831 }
832
fileTransferFailed(MSN::FileTransferInvitation * inv,int error,string message)833 void msncallbacks::fileTransferFailed(MSN::FileTransferInvitation * inv, int error, string message) {
834 ::log("msncallbacks::fileTransferFailed");
835 imfile fr;
836
837 if(mhook.getfevent(inv, fr)) {
838 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsError, 0, 0);
839 mhook.transferinfo.erase(fr);
840 }
841 }
842
fileTransferSucceeded(MSN::FileTransferInvitation * inv)843 void msncallbacks::fileTransferSucceeded(MSN::FileTransferInvitation * inv) {
844 ::log("msncallbacks::fileTransferSucceeded");
845 imfile fr;
846
847 if(mhook.getfevent(inv, fr)) {
848 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsFinish, 0, 0);
849 mhook.transferinfo.erase(fr);
850 }
851 }
852
gotNewConnection(MSN::Connection * conn)853 void msncallbacks::gotNewConnection(MSN::Connection * conn) {
854 ::log("msncallbacks::gotNewConnection");
855 if(dynamic_cast<MSN::NotificationServerConnection *>(conn))
856 dynamic_cast<MSN::NotificationServerConnection *>(conn)->synchronizeLists();
857 }
858
closingConnection(MSN::Connection * conn)859 void msncallbacks::closingConnection(MSN::Connection * conn) {
860 ::log("msncallbacks::closingConnection");
861
862 MSN::SwitchboardServerConnection *swc;
863
864 if(swc = dynamic_cast<MSN::SwitchboardServerConnection *>(conn)) {
865 map<string, MSN::SwitchboardServerConnection *>::const_iterator ic = mhook.lconn.begin();
866 while(ic != mhook.lconn.end()) {
867 if(swc == ic->second) {
868 mhook.lconn.erase(ic->first);
869 break;
870 }
871 ++ic;
872 }
873
874 } else if(conn == &mhook.conn) {
875 if(!mhook.destroying) {
876 mhook.rfds.clear();
877 mhook.wfds.clear();
878 mhook.lconn.clear();
879 mhook.slst.clear();
880
881 if(mhook.logged()) {
882 logger.putourstatus(msn, mhook.getstatus(), mhook.ourstatus = offline);
883 clist.setoffline(msn);
884
885 mhook.fonline = false;
886 mhook.log(abstracthook::logDisconnected);
887
888 face.update();
889 }
890 }
891 }
892
893 unregisterSocket(conn->sock);
894 }
895
changedStatus(MSN::Connection * conn,MSN::BuddyStatus state)896 void msncallbacks::changedStatus(MSN::Connection * conn, MSN::BuddyStatus state) {
897 ::log("msncallbacks::changedStatus");
898 }
899
connectToServer(string server,int port,bool * connected)900 int msncallbacks::connectToServer(string server, int port, bool *connected) {
901 ::log("msncallbacks::connectToServer");
902 struct sockaddr_in sa;
903 struct hostent *hp;
904 int a, s;
905 string msgerr = _("+ [msn] cannot connect: ");
906
907 hp = gethostbyname(server.c_str());
908 if(!hp) {
909 face.log(msgerr + _("could not resolve hostname"));
910 errno = ECONNREFUSED;
911 return -1;
912 }
913
914 memset(&sa, 0, sizeof(sa));
915 memcpy((char *) &sa.sin_addr, hp->h_addr, hp->h_length);
916 sa.sin_family = hp->h_addrtype;
917 sa.sin_port = htons((u_short) port);
918
919 if((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
920 return -1;
921
922 int oldfdArgs = fcntl(s, F_GETFL, 0);
923 fcntl(s, F_SETFL, oldfdArgs | O_NONBLOCK);
924
925 *connected = false;
926
927 if(cw_connect(s, (struct sockaddr *) &sa, sizeof sa, 0) < 0) {
928 if(errno != EINPROGRESS) {
929 face.log(msgerr + _("verify the hostname and port"));
930 close(s);
931 return -1;
932 }
933 }
934
935 return s;
936 }
937
listenOnPort(int port)938 int msncallbacks::listenOnPort(int port) {
939 ::log("msncallbacks::listenOnPort");
940 int s;
941 struct sockaddr_in addr;
942
943 if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
944 return -1;
945
946 memset(&addr, 0, sizeof(addr));
947 addr.sin_family = AF_INET;
948 addr.sin_port = htons(port);
949
950 if(bind(s, (sockaddr *) &addr, sizeof(addr)) < 0 || listen(s, 1) < 0) {
951 close(s);
952 return -1;
953 }
954
955 return s;
956 }
957
getOurIP()958 string msncallbacks::getOurIP() {
959 ::log("msncallbacks::getOurIP");
960 struct hostent *hn;
961 char buf2[1024];
962
963 gethostname(buf2, 1024);
964 hn = gethostbyname(buf2);
965
966 return inet_ntoa(*((struct in_addr*) hn->h_addr));
967 }
968
getSecureHTTPProxy()969 string msncallbacks::getSecureHTTPProxy() {
970 ::log("msncallbacks::getSecureHTTPProxy");
971 return "";
972 }
973
addedGroup(MSN::Connection * conn,string groupName,int groupID)974 void msncallbacks::addedGroup(MSN::Connection * conn, string groupName, int groupID) {
975 ::log("msncallbacks::addedGroup");
976 int i;
977 icqcontact *c;
978
979 mhook.mgroups[groupID] = groupName;
980
981 vector<icqgroup>::const_iterator ig = groups.begin();
982
983 while(ig != groups.end()) {
984 if(ig->getname() == groupName) {
985 for(i = 0; i < clist.count; i++) {
986 c = (icqcontact *) clist.at(i);
987 if(c->getgroupid() == ig->getid())
988 mhook.sendnewuser(c->getdesc());
989 }
990 break;
991 }
992 ++ig;
993 }
994 }
995
renamedGroup(MSN::Connection * conn,int groupID,string newGroupName)996 void msncallbacks::renamedGroup(MSN::Connection * conn, int groupID, string newGroupName) {
997 ::log("msncallbacks::renamedGroup");
998 mhook.mgroups[groupID] = newGroupName;
999 }
1000
removedGroup(MSN::Connection * conn,int groupID)1001 void msncallbacks::removedGroup(MSN::Connection * conn, int groupID) {
1002 ::log("msncallbacks::removedGroup");
1003 mhook.mgroups.erase(groupID);
1004 }
1005
1006 #endif
1007