connwrap - initialize gnutls session in cw_connect
[centerim.git] / src / hooks / msnhook.cc
blob4aa906e0cc214fe4676b499d6647990a8578b566
1 /*
3 * centerim MSN protocol handling class
4 * $Id: msnhook.cc,v 1.91 2005/02/03 02:02:37 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_MSN
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"
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>
46 msnhook mhook;
48 static string nicknormalize(const string &nick) {
49 if(nick.find("@") == -1) return nick + "@hotmail.com";
50 return nick;
53 static string nicktodisp(const string &nick) {
54 int pos;
55 string r = nick;
57 if((pos = r.find("@")) != -1)
58 if(r.substr(pos+1) == "hotmail.com")
59 r.erase(pos);
61 return r;
64 static map<MSN::BuddyStatus, imstatus> convstat;
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;
71 return offline;
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;
82 return MSN::STATUS_AVAILABLE;
85 // ----------------------------------------------------------------------------
87 msnhook::msnhook(): abstracthook(msn), conn(cb) {
88 ourstatus = offline;
89 fonline = false;
90 destroying = false;
92 fcapabs.insert(hookcapab::changedetails);
93 fcapabs.insert(hookcapab::directadd);
96 msnhook::~msnhook() {
97 if(conn.connectionState() != MSN::NotificationServerConnection::NS_DISCONNECTED) {
98 destroying = true;
99 conn.disconnect();
103 void msnhook::init() {
104 manualstatus = conf->getstatus(msn);
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;
116 void msnhook::connect() {
117 icqconf::imaccount account = conf->getourid(msn);
119 log(logConnecting);
121 readinfo = flogged = false;
122 fonline = true;
124 try {
125 if(conn.connectionState() != MSN::NotificationServerConnection::NS_DISCONNECTED)
126 conn.disconnect();
128 rfds.clear();
129 wfds.clear();
131 conn.connect(account.server, account.port, nicknormalize(account.nickname), account.password);
132 } catch(...) {
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);
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(...) {
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;
163 FD_ZERO(&rs);
164 FD_ZERO(&ws);
165 FD_ZERO(&es);
167 getsockets(rs, ws, es, hsock);
168 tv.tv_sec = tv.tv_usec = 0;
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;
179 for(i = wfds.begin(); i != wfds.end(); ++i)
180 if(FD_ISSET(*i, &ws)) {
181 c = conn.connectionWithSocket(*i);
183 if(c) {
184 if(!c->isConnected()) {
185 c->socketConnectionCompleted();
186 } else {
187 c->socketIsWritable();
191 return;
194 } catch(...) {
198 void msnhook::getsockets(fd_set &rf, fd_set &wf, fd_set &efds, int &hsocket) const {
199 vector<int>::const_iterator i;
201 for(i = rfds.begin(); i != rfds.end(); ++i) {
202 hsocket = max(hsocket, *i);
203 FD_SET(*i, &rf);
206 for(i = wfds.begin(); i != wfds.end(); ++i) {
207 hsocket = max(hsocket, *i);
208 FD_SET(*i, &wf);
212 bool msnhook::isoursocket(fd_set &rf, fd_set &wf, fd_set &efds) const {
213 vector<int>::const_iterator i;
215 for(i = rfds.begin(); i != rfds.end(); ++i)
216 if(FD_ISSET(*i, &rf))
217 return true;
219 for(i = wfds.begin(); i != wfds.end(); ++i)
220 if(FD_ISSET(*i, &wf))
221 return true;
223 return false;
226 bool msnhook::online() const {
227 return fonline;
230 bool msnhook::logged() const {
231 return fonline && flogged;
234 bool msnhook::isconnecting() const {
235 return fonline && !flogged;
238 bool msnhook::enabled() const {
239 return true;
242 bool msnhook::send(const imevent &ev) {
243 string text;
244 string rcpt = nicknormalize(ev.getcontact().nickname);
246 if(ev.gettype() == imevent::message) {
247 const immessage *m = static_cast<const immessage *>(&ev);
248 if(m) text = m->gettext();
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();
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;
259 for(ir = files.begin(); ir != files.end(); ++ir) {
260 imfile::record r;
262 r.fname = ir->fname;
263 r.size = ir->size;
265 imfile fr(ev.getcontact(), imevent::outgoing, "", vector<imfile::record>(1, r));
267 try {
268 qevent *ctx = new qevent(qevent::qeFile, rcpt, ir->fname);
270 if(lconn.find(rcpt) != lconn.end()) sendmsn(lconn[rcpt], ctx);
271 else conn.requestSwitchboardConnection(ctx);
273 } catch(...) {
277 return true;
280 icqcontact *c = clist.get(ev.getcontact());
281 text = rusconv("ku", text);
283 if(c)
284 if(c->getstatus() != offline || !c->inlist()) {
285 try {
286 qevent *ctx = new qevent(qevent::qeMsg, rcpt, text);
288 if(lconn.find(rcpt) != lconn.end()) sendmsn(lconn[rcpt], ctx);
289 else conn.requestSwitchboardConnection(ctx);
291 } catch(...) {
294 return true;
297 return false;
300 int msnhook::findgroup(const imcontact &ic, string &gname) const {
301 int gid = -1;
302 icqcontact *c;
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;
317 return gid;
320 void msnhook::sendnewuser(const imcontact &ic) {
321 if(logged() && !readinfo) {
322 icqcontact *c;
323 imcontact icc(nicktodisp(ic.nickname), msn);
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);
332 int gid;
333 string gname;
335 gid = findgroup(ic, gname);
337 try {
338 if(gid == -1) {
339 gid = 0;
341 conn.addToGroup(nicknormalize(ic.nickname), gid);
342 } catch(...) {
346 requestinfo(ic);
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(...) {
360 } else {
361 if(getstatus() != offline) {
362 disconnect();
367 imstatus msnhook::getstatus() const {
368 return online() ? ourstatus : offline;
371 void msnhook::removeuser(const imcontact &ic) {
372 removeuser(ic, true);
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));
380 if(online() && ib != slst["FL"].end()) {
381 if(report)
382 log(logContactRemove, ic.nickname.c_str());
384 try {
385 conn.removeFromGroup(nicknormalize(ic.nickname), ib->gid);
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];
393 if(!found && ib->gid > 0)
394 conn.removeGroup(ib->gid);
395 } catch(...) {
400 void msnhook::requestinfo(const imcontact &ic) {
401 icqcontact *c = clist.get(ic);
402 if(!c) c = clist.get(contactroot);
404 icqcontact::moreinfo m = c->getmoreinfo();
405 icqcontact::basicinfo b = c->getbasicinfo();
407 b.email = nicknormalize(ic.nickname);
408 m.homepage = "http://members.msn.com/" + b.email;
410 if(ic.nickname == conf->getourid(msn).nickname)
411 c->setnick(friendlynicks[ic.nickname]);
413 c->setmoreinfo(m);
414 c->setbasicinfo(b);
417 void msnhook::lookup(const imsearchparams &params, verticalmenu &dest) {
418 if(params.reverse) {
419 vector<msnbuddy>::const_iterator i = slst["RL"].begin();
421 while(i != slst["RL"].end()) {
422 icqcontact *c = new icqcontact(imcontact(nicktodisp(i->nick), msn));
423 c->setnick(i->friendly);
425 dest.additem(conf->getcolor(cp_clist_msn), c, (string) " " + i->nick);
426 ++i;
428 face.findready();
430 face.log(_("+ [msn] reverse users listing finished, %d found"),
431 slst["RL"].size());
433 dest.redraw();
437 vector<icqcontact *> msnhook::getneedsync() {
438 int i;
439 vector<icqcontact *> r;
440 bool found;
442 for(i = 0; i < clist.count; i++) {
443 icqcontact *c = (icqcontact *) clist.at(i);
445 if(c->getdesc().pname == msn) {
446 vector<msnbuddy>::const_iterator fi = slst["FL"].begin();
448 for(found = false; fi != slst["FL"].end() && !found; ++fi)
449 found = c->getdesc().nickname == fi->nick;
451 if(!found)
452 r.push_back(c);
456 return r;
459 void msnhook::sendupdateuserinfo(const icqcontact &c) {
460 try {
461 conn.setFriendlyName(c.getnick());
462 } catch(...) {
466 void msnhook::checkfriendly(icqcontact *c, const string friendlynick, bool forcefetch) {
467 string oldnick = c->getnick();
468 string newnick = unmime(friendlynick);
470 c->setnick(newnick);
472 if(forcefetch || (oldnick != newnick && c->getdispnick() == oldnick) || oldnick.empty()) {
473 c->setdispnick(newnick);
474 face.relaxedupdate();
478 void msnhook::checkinlist(imcontact ic) {
479 icqcontact *c = clist.get(ic);
480 vector<icqcontact *> notremote = getneedsync();
482 if(c)
483 if(c->inlist())
484 if(find(notremote.begin(), notremote.end(), c) != notremote.end())
485 mhook.sendnewuser(ic);
488 bool msnhook::knowntransfer(const imfile &fr) const {
489 return transferinfo.find(fr) != transferinfo.end();
492 void msnhook::replytransfer(const imfile &fr, bool accept, const string &localpath) {
493 if(accept) {
494 transferinfo[fr].second = localpath;
496 if(transferinfo[fr].second.substr(transferinfo[fr].second.size()-1) != "/")
497 transferinfo[fr].second += "/";
499 transferinfo[fr].second += justfname(fr.getfiles().begin()->fname);
500 // msn_filetrans_accept(transferinfo[fr].first, transferinfo[fr].second.c_str());
502 } else {
503 // msn_filetrans_reject(transferinfo[fr].first);
504 transferinfo.erase(fr);
509 void msnhook::aborttransfer(const imfile &fr) {
510 // msn_filetrans_reject(transferinfo[fr].first);
512 face.transferupdate(fr.getfiles().begin()->fname, fr,
513 icqface::tsCancel, 0, 0);
515 transferinfo.erase(fr);
518 bool msnhook::getfevent(MSN::FileTransferInvitation *fhandle, imfile &fr) {
519 map<imfile, pair<MSN::FileTransferInvitation *, string> >::const_iterator i = transferinfo.begin();
521 while(i != transferinfo.end()) {
522 if(i->second.first == fhandle) {
523 fr = i->first;
524 return true;
526 ++i;
529 return false;
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);
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(...) {
543 sendnewuser(c->getdesc());
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(...) {
557 break;
559 ++im;
564 // ----------------------------------------------------------------------------
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;
571 if(forcefetch = !c)
572 c = clist.addnew(ic, false);
574 if(!friendlyname.empty())
575 checkfriendly(c, friendlyname, forcefetch);
577 logger.putonline(ic, c->getstatus(), status);
578 c->setstatus(status);
581 // ----------------------------------------------------------------------------
583 void msnhook::sendmsn(MSN::SwitchboardServerConnection *conn, const qevent *ctx) {
584 MSN::FileTransferInvitation *inv;
586 switch(ctx->type) {
587 case msnhook::qevent::qeMsg:
588 conn->sendMessage(ctx->text);
589 break;
591 case msnhook::qevent::qeFile:
592 inv = conn->sendFile(ctx->text);
593 // if(inv) mhook.transferinfo[] = inv;
594 break;
597 delete ctx;
600 // ----------------------------------------------------------------------------
602 static void log(const string &s) {
603 if(conf->getdebug())
604 face.log(s);
607 void msncallbacks::log(int writing, const char* buf) {
608 string pref = writing ? "OUT" : "IN";
609 ::log((string) "[" + pref + "] " + buf);
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);
618 void msncallbacks::unregisterSocket(int s) {
619 ::log("msncallbacks::unregisterSocket");
620 vector<int>::iterator i;
622 i = find(mhook.rfds.begin(), mhook.rfds.end(), s);
623 if(i != mhook.rfds.end()) mhook.rfds.erase(i);
625 i = find(mhook.wfds.begin(), mhook.wfds.end(), s);
626 if(i != mhook.wfds.end()) mhook.wfds.erase(i);
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;
635 void msncallbacks::gotBuddyListInfo(MSN::NotificationServerConnection * conn, MSN::ListSyncInfo * data) {
636 ::log("msncallbacks::gotBuddyListInfo");
637 imcontact ic;
638 bool found;
640 mhook.readinfo = true;
642 std::map<int, MSN::Group>::iterator ig;
644 for(ig = data->groups.begin(); ig != data->groups.end(); ig++) {
645 mhook.mgroups[ig->second.groupID] = ig->second.name;
648 std::list<MSN::Buddy> &lst = data->forwardList;
649 std::list<MSN::Buddy>::iterator i;
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));
656 ic = imcontact(nicktodisp(i->userName), msn);
657 icqcontact *c = clist.get(ic);
658 if(!c) c = clist.addnew(ic, false);
660 icqcontact::basicinfo bi = c->getbasicinfo();
661 icqcontact::workinfo wi = c->getworkinfo();
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;
670 c->setbasicinfo(bi);
671 c->setworkinfo(wi);
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);
679 for(lst = data->reverseList, i = lst.begin(); i != lst.end(); ++i)
680 mhook.slst["RL"].push_back(msnbuddy(i->userName, i->friendlyName));
682 mhook.readinfo = false;
683 mhook.flogged = true;
685 mhook.setautostatus(mhook.manualstatus);
686 mhook.timer_ping = timer_current;
687 mhook.log(abstracthook::logLogged);
688 face.update();
691 void msncallbacks::gotLatestListSerial(MSN::Connection * conn, int serial) {
692 ::log("msncallbacks::gotLatestListSerial");
695 void msncallbacks::gotGTC(MSN::Connection * conn, char c) {
696 ::log("msncallbacks::gotGTC");
699 void msncallbacks::gotBLP(MSN::Connection * conn, char c) {
700 ::log("msncallbacks::gotBLP");
703 void msncallbacks::gotNewReverseListEntry(MSN::Connection * conn, MSN::Passport buddy, std::string friendlyname) {
704 ::log("msncallbacks::gotNewReverseListEntry");
706 try {
707 mhook.conn.addToList("AL", buddy);
708 } catch(...) {
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")));
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));
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;
734 void msncallbacks::showError(MSN::Connection * conn, string msg) {
735 ::log(msg);
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));
743 void msncallbacks::buddyOffline(MSN::Connection * conn, MSN::Passport buddy) {
744 ::log("msncallbacks::buddyOffline");
745 mhook.statusupdate(buddy, "", offline);
748 void msncallbacks::gotSwitchboard(MSN::SwitchboardServerConnection * conn, const void * tag) {
749 ::log("msncallbacks::gotSwitchboard");
751 if(tag) {
752 const msnhook::qevent *ctx = static_cast<const msnhook::qevent *>(tag);
753 conn->inviteUser(ctx->nick);
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;
767 void msncallbacks::buddyLeftConversation(MSN::SwitchboardServerConnection * conn, MSN::Passport buddy) {
768 ::log("msncallbacks::buddyLeftConversation");
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);
775 mhook.checkinlist(ic);
777 string text = mhook.rusconv("uk", msg->getBody());
778 em.store(immessage(ic, imevent::incoming, text));
781 void msncallbacks::failedSendingMessage(MSN::Connection * conn) {
782 ::log("msncallbacks::failedSendingMessage");
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);
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);
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);
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;
808 imfile::record r;
809 r.fname = inv->fileName;
810 r.size = inv->fileSize;
812 imcontact ic(nicktodisp(buddy), msn);
813 mhook.checkinlist(ic);
815 imfile fr(ic, imevent::incoming, "", vector<imfile::record>(1, r));
817 mhook.transferinfo[fr].first = inv;
818 em.store(fr);
820 face.transferupdate(inv->fileName, fr, icqface::tsInit, inv->fileSize, 0);
823 void msncallbacks::fileTransferProgress(MSN::FileTransferInvitation * inv, string status, unsigned long recv, unsigned long total) {
824 ::log("msncallbacks::fileTransferProgress");
825 imfile fr;
827 if(mhook.getfevent(inv, fr)) {
828 face.transferupdate(fr.getfiles().begin()->fname, fr,
829 icqface::tsProgress, total, recv);
833 void msncallbacks::fileTransferFailed(MSN::FileTransferInvitation * inv, int error, string message) {
834 ::log("msncallbacks::fileTransferFailed");
835 imfile fr;
837 if(mhook.getfevent(inv, fr)) {
838 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsError, 0, 0);
839 mhook.transferinfo.erase(fr);
843 void msncallbacks::fileTransferSucceeded(MSN::FileTransferInvitation * inv) {
844 ::log("msncallbacks::fileTransferSucceeded");
845 imfile fr;
847 if(mhook.getfevent(inv, fr)) {
848 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsFinish, 0, 0);
849 mhook.transferinfo.erase(fr);
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();
859 void msncallbacks::closingConnection(MSN::Connection * conn) {
860 ::log("msncallbacks::closingConnection");
862 MSN::SwitchboardServerConnection *swc;
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;
871 ++ic;
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();
881 if(mhook.logged()) {
882 logger.putourstatus(msn, mhook.getstatus(), mhook.ourstatus = offline);
883 clist.setoffline(msn);
885 mhook.fonline = false;
886 mhook.log(abstracthook::logDisconnected);
888 face.update();
893 unregisterSocket(conn->sock);
896 void msncallbacks::changedStatus(MSN::Connection * conn, MSN::BuddyStatus state) {
897 ::log("msncallbacks::changedStatus");
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: ");
907 hp = gethostbyname(server.c_str());
908 if(!hp) {
909 face.log(msgerr + _("could not resolve hostname"));
910 errno = ECONNREFUSED;
911 return -1;
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);
919 if((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
920 return -1;
922 int oldfdArgs = fcntl(s, F_GETFL, 0);
923 fcntl(s, F_SETFL, oldfdArgs | O_NONBLOCK);
925 *connected = false;
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;
935 return s;
938 int msncallbacks::listenOnPort(int port) {
939 ::log("msncallbacks::listenOnPort");
940 int s;
941 struct sockaddr_in addr;
943 if((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
944 return -1;
946 memset(&addr, 0, sizeof(addr));
947 addr.sin_family = AF_INET;
948 addr.sin_port = htons(port);
950 if(bind(s, (sockaddr *) &addr, sizeof(addr)) < 0 || listen(s, 1) < 0) {
951 close(s);
952 return -1;
955 return s;
958 string msncallbacks::getOurIP() {
959 ::log("msncallbacks::getOurIP");
960 struct hostent *hn;
961 char buf2[1024];
963 gethostname(buf2, 1024);
964 hn = gethostbyname(buf2);
966 return inet_ntoa(*((struct in_addr*) hn->h_addr));
969 string msncallbacks::getSecureHTTPProxy() {
970 ::log("msncallbacks::getSecureHTTPProxy");
971 return "";
974 void msncallbacks::addedGroup(MSN::Connection * conn, string groupName, int groupID) {
975 ::log("msncallbacks::addedGroup");
976 int i;
977 icqcontact *c;
979 mhook.mgroups[groupID] = groupName;
981 vector<icqgroup>::const_iterator ig = groups.begin();
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());
990 break;
992 ++ig;
996 void msncallbacks::renamedGroup(MSN::Connection * conn, int groupID, string newGroupName) {
997 ::log("msncallbacks::renamedGroup");
998 mhook.mgroups[groupID] = newGroupName;
1001 void msncallbacks::removedGroup(MSN::Connection * conn, int groupID) {
1002 ::log("msncallbacks::removedGroup");
1003 mhook.mgroups.erase(groupID);
1006 #endif