Improve yahoo login verbosity
[centerim.git] / src / hooks / yahoohook.cc
bloba7d1d64b91e6b3f6d2b932eebc07f85b6bcfb39e
1 /*
3 * centerim yahoo! protocol handling class
4 * $Id: yahoohook.cc,v 1.112 2004/12/20 00:54:02 konst Exp $
6 * Copyright (C) 2003-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_YAHOO
29 #include "yahoohook.h"
30 #include "icqmlist.h"
31 #include "icqface.h"
32 #include "imlogger.h"
34 #include "icqcontacts.h"
35 #include "icqgroups.h"
37 #include "accountmanager.h"
38 #include "eventmanager.h"
40 #include "yahoo2.h"
41 #include "connwrap.h"
43 #include <netdb.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
47 #define PERIOD_REFRESH 60
48 #define PERIOD_CLOSE 6
50 #define NOTIFBUF 512
52 int yahoohook::yfd::connection_tags = 0;
54 char pager_host[255], pager_port[255], filetransfer_host[255],
55 filetransfer_port[255], webcam_host[255], webcam_port[255],
56 local_host[255], webcam_description[255];
58 int conn_type;
60 yahoohook yhook;
62 static int stat2int[imstatus_size] = {
63 YAHOO_STATUS_OFFLINE,
64 YAHOO_STATUS_AVAILABLE,
65 YAHOO_STATUS_INVISIBLE,
66 YAHOO_STATUS_CUSTOM,
67 YAHOO_STATUS_BUSY,
68 YAHOO_STATUS_NOTATDESK,
69 YAHOO_STATUS_NOTATHOME,
70 YAHOO_STATUS_IDLE,
71 YAHOO_STATUS_OUTTOLUNCH,
74 yahoohook::yahoohook() : abstracthook(yahoo), fonline(false), cid(0) {
75 fcapabs.insert(hookcapab::setaway);
76 fcapabs.insert(hookcapab::fetchaway);
77 fcapabs.insert(hookcapab::directadd);
78 fcapabs.insert(hookcapab::files);
79 fcapabs.insert(hookcapab::conferencing);
80 fcapabs.insert(hookcapab::conferencesaretemporary);
82 pager_host[0] = pager_port[0] = filetransfer_host[0] =
83 filetransfer_port[0] = webcam_host[0] = webcam_port[0] =
84 local_host[0] = 0;
87 yahoohook::~yahoohook() {
90 void yahoohook::init() {
91 manualstatus = conf->getstatus(proto);
93 static struct yahoo_callbacks c;
95 memset(&c, 0, sizeof(c));
97 c.ext_yahoo_login_response = &login_response;
98 c.ext_yahoo_got_buddies = &got_buddies;
99 c.ext_yahoo_status_changed = &status_changed;
100 c.ext_yahoo_got_im = &got_im;
101 c.ext_yahoo_got_conf_invite = &got_conf_invite;
102 c.ext_yahoo_conf_userdecline = &conf_userdecline;
103 c.ext_yahoo_conf_userjoin = &conf_userjoin;
104 c.ext_yahoo_conf_userleave = &conf_userleave;
105 c.ext_yahoo_conf_message = &conf_message;
106 c.ext_yahoo_got_file = &got_file;
107 c.ext_yahoo_contact_added = &contact_added;
108 c.ext_yahoo_game_notify = &game_notify;
109 c.ext_yahoo_mail_notify = &mail_notify;
110 c.ext_yahoo_system_message = &system_message;
111 c.ext_yahoo_error = &error;
112 c.ext_yahoo_add_handler = &add_handler;
113 c.ext_yahoo_remove_handler = &remove_handler;
114 c.ext_yahoo_connect_async = &connect_async;
115 c.ext_yahoo_got_identities = &got_identities;
116 c.ext_yahoo_got_ignore = &got_ignore;
117 c.ext_yahoo_got_cookies = &got_cookies;
118 c.ext_yahoo_chat_cat_xml = &chat_cat_xml;
119 c.ext_yahoo_chat_join = &chat_join;
120 c.ext_yahoo_chat_userjoin = &chat_userjoin;
121 c.ext_yahoo_chat_userleave = &chat_userleave;
122 c.ext_yahoo_chat_message = &chat_message;
123 c.ext_yahoo_rejected = &rejected;
124 c.ext_yahoo_typing_notify = &typing_notify;
125 c.ext_yahoo_got_webcam_image = &got_webcam_image;
126 c.ext_yahoo_webcam_invite = &webcam_invite;
127 c.ext_yahoo_webcam_invite_reply = &webcam_invite_reply;
128 c.ext_yahoo_webcam_closed = &webcam_closed;
129 c.ext_yahoo_webcam_viewer = &webcam_viewer;
130 c.ext_yahoo_webcam_data_request = &webcam_data_request;
131 c.ext_yahoo_got_search_result = &got_search_result;
132 c.ext_yahoo_got_auth_request = &auth_request;
133 c.ext_yahoo_got_auth_response = &auth_response;
134 c.ext_yahoo_log = &ylog;
136 yahoo_register_callbacks(&c);
139 void yahoohook::connect() {
140 icqconf::imaccount acc = conf->getourid(proto);
141 int r;
143 log(logConnecting);
145 if(cid < 0) {
146 yahoo_logoff(cid);
147 yahoo_close(cid);
150 cid = yahoo_init_with_attributes(acc.nickname.c_str(), acc.password.c_str(),
151 "pager_host", acc.server.c_str(),
152 "pager_port", acc.port, (char *) NULL);
154 yahoo_login(cid, stat2int[manualstatus]);
156 if(cid < 0) {
157 string msg = _("+ [yahoo] cannot connect: ");
159 switch(cid) {
160 case -1: msg += _("could not resolve hostname"); break;
161 case -2: msg += _("could not create socket"); break;
162 default: msg += _("verify the pager host and port entered"); break;
165 face.log(msg);
166 } else {
167 fonline = true;
168 flogged = false;
172 void yahoohook::main() {
173 vector<yfd>::iterator i;
174 struct timeval tv;
175 int hsock;
176 fd_set rs, ws, es;
178 FD_ZERO(&rs);
179 FD_ZERO(&ws);
180 FD_ZERO(&es);
182 tv.tv_sec = tv.tv_usec = 0;
183 hsock = 0;
185 for(i = rfds.begin(); i != rfds.end(); ++i) {
186 FD_SET(i->fd, &rs);
187 hsock = max(hsock, i->fd);
190 for(i = wfds.begin(); i != wfds.end(); ++i) {
191 FD_SET(i->fd, &ws);
192 hsock = max(hsock, i->fd);
195 if(select(hsock+1, &rs, &ws, 0, &tv) > 0) {
196 for(i = rfds.begin(); i != rfds.end(); ++i) {
197 if(FD_ISSET(i->fd, &rs)) {
198 yahoo_read_ready(cid, i->fd, i->data);
199 break;
203 for(i = wfds.begin(); i != wfds.end(); ++i) {
204 if(FD_ISSET(i->fd, &ws)) {
205 if(i->isconnect) {
206 connect_complete(i->data, i->fd);
207 } else {
208 yahoo_write_ready(cid, i->fd, i->data);
210 break;
216 void yahoohook::getsockets(fd_set &rs, fd_set &ws, fd_set &es, int &hsocket) const {
217 if(online()) {
218 vector<yfd>::const_iterator i;
220 for(i = rfds.begin(); i != rfds.end(); ++i) {
221 hsocket = max(hsocket, i->fd);
222 FD_SET(i->fd, &rs);
225 for(i = wfds.begin(); i != wfds.end(); ++i) {
226 hsocket = max(hsocket, i->fd);
227 FD_SET(i->fd, &ws);
232 bool yahoohook::isoursocket(fd_set &rs, fd_set &ws, fd_set &es) const {
233 vector<yfd>::const_iterator i;
235 for(i = rfds.begin(); i != rfds.end(); ++i)
236 if(FD_ISSET(i->fd, &rs))
237 return true;
239 for(i = wfds.begin(); i != wfds.end(); ++i)
240 if(FD_ISSET(i->fd, &ws))
241 return true;
243 return false;
246 void yahoohook::disconnect() {
247 if(online()) {
248 yahoo_logoff(cid);
249 time(&timer_close);
253 void yahoohook::disconnected() {
254 if(logged()) {
255 rfds.clear();
256 wfds.clear();
258 logger.putourstatus(proto, getstatus(), ourstatus = offline);
259 clist.setoffline(proto);
260 fonline = false;
261 log(logDisconnected);
262 face.update();
266 void yahoohook::exectimers() {
267 vector<pair<Action, string> >::iterator it;
269 for(it = tobedone.begin(); it != tobedone.end(); ++it) {
270 switch(it->first) {
271 case tbdConfLogon:
272 /* TODO: investigate if copy is really needed here */
273 char *room = strdup(it->second.c_str());
274 yahoo_conference_logon(cid, 0, getmembers(it->second), room);
275 free (room);
276 break;
280 tobedone.clear();
282 if(logged()) {
283 if(timer_current-timer_refresh > PERIOD_REFRESH) {
284 yahoo_refresh(cid);
285 timer_refresh = timer_current;
287 } else if(timer_close && timer_current-timer_close > PERIOD_CLOSE) {
288 yahoo_close(cid);
289 disconnected();
295 struct tm *yahoohook::timestamp() {
296 return localtime(&timer_current);
299 bool yahoohook::send(const imevent &ev) {
300 icqcontact *c = clist.get(ev.getcontact());
301 string text;
303 if(c) {
304 if(ev.gettype() == imevent::message) {
305 const immessage *m = static_cast<const immessage *>(&ev);
306 if(m) text = rushtmlconv("ku", m->gettext());
308 } else if(ev.gettype() == imevent::url) {
309 const imurl *m = static_cast<const imurl *>(&ev);
310 if(m) text = rushtmlconv("ku", m->geturl()) + "\n\n" + rusconv("kw", m->getdescription());
312 } else if(ev.gettype() == imevent::file) {
313 const imfile *m = static_cast<const imfile *>(&ev);
314 vector<imfile::record> files = m->getfiles();
315 vector<imfile::record>::const_iterator ir;
317 for(ir = files.begin(); ir != files.end(); ++ir) {
318 sfiles.push_back(strdup(ir->fname.c_str()));
319 srfiles[sfiles.back()] = *m;
321 yahoo_send_file(cid, ev.getcontact().nickname.c_str(),
322 m->getmessage().c_str(), justfname(ir->fname).c_str(),
323 ir->size, &get_fd, sfiles.back());
326 return true;
327 } else if (ev.gettype() == imevent::authorization) {
328 const imauthorization *m = static_cast<const imauthorization *> (&ev);
330 switch(m->getauthtype()) {
331 case imauthorization::Granted:
332 yahoo_auth_grant(cid, ev.getcontact().nickname.c_str());
333 break;
335 case imauthorization::Rejected:
336 yahoo_auth_deny(cid, ev.getcontact().nickname.c_str());
337 break;
340 return true;
343 if(!ischannel(c)) {
344 yahoo_send_im(cid, 0, ev.getcontact().nickname.c_str(), text.c_str(), 0, 0);
345 } else {
346 yahoo_conference_message(cid, 0, getmembers(ev.getcontact().nickname.substr(1)),
347 ev.getcontact().nickname.c_str()+1, text.c_str(), 0);
350 return true;
353 return false;
356 bool yahoohook::online() const {
357 return fonline;
360 bool yahoohook::logged() const {
361 return fonline && flogged;
364 bool yahoohook::isconnecting() const {
365 return fonline && !flogged;
368 void yahoohook::sendnewuser(const imcontact &ic) {
369 sendnewuser(ic, true);
372 void yahoohook::sendnewuser(const imcontact &ic, bool report) {
373 if(online() && !ischannel(ic)) {
374 if(logged()) {
375 bool found = false;
376 const YList *buddies = yahoo_get_buddylist(cid);
377 const YList *bud = 0;
379 for(bud = buddies; bud && !found; bud = y_list_next(bud))
380 found = ic.nickname == static_cast<yahoo_buddy *>(bud->data)->id;
382 if(!found) {
383 if(report) log(logContactAdd, ic.nickname.c_str());
384 if (groups.size()>0)
386 vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), clist.get(ic)->getgroupid());
387 if (ig == groups.end())
388 ig = groups.begin();
389 yahoo_add_buddy(cid, ic.nickname.c_str(), ig->getname().c_str(), "");
395 requestinfo(ic);
398 void yahoohook::removeuser(const imcontact &ic) {
399 removeuser(ic, true);
402 void yahoohook::removeuser(const imcontact &ic, bool report) {
403 if(logged()) {
404 if(!ischannel(ic)) {
405 if(report) log(logContactRemove, ic.nickname.c_str());
407 const YList *buddies = yahoo_get_buddylist(cid);
408 const YList *bud = 0;
410 for(bud = buddies; bud; bud = y_list_next(bud)) {
411 if(ic.nickname == ((yahoo_buddy *) bud->data)->id)
412 yahoo_remove_buddy(cid,
413 ((yahoo_buddy *) bud->data)->id,
414 ((yahoo_buddy *) bud->data)->group);
416 } else {
417 if(report)
418 face.log(_("+ [yahoo] leaving the %s conference"),
419 ic.nickname.c_str());
421 yahoo_conference_logoff(cid, 0, getmembers(ic.nickname.substr(1)), ic.nickname.c_str()+1);
426 imstatus yahoohook::yahoo2imstatus(int status) {
427 imstatus st = offline;
429 switch(status) {
430 case YAHOO_STATUS_AVAILABLE:
431 st = available;
432 break;
433 case YAHOO_STATUS_BUSY:
434 st = dontdisturb;
435 break;
436 case YAHOO_STATUS_CUSTOM:
437 case YAHOO_STATUS_BRB:
438 case YAHOO_STATUS_IDLE:
439 case YAHOO_STATUS_ONPHONE:
440 st = away;
441 break;
442 case YAHOO_STATUS_NOTATDESK:
443 st = occupied;
444 break;
445 case YAHOO_STATUS_NOTATHOME:
446 case YAHOO_STATUS_NOTINOFFICE:
447 case YAHOO_STATUS_ONVACATION:
448 case YAHOO_STATUS_STEPPEDOUT:
449 st = notavail;
450 break;
451 case YAHOO_STATUS_OUTTOLUNCH:
452 st = outforlunch;
453 break;
454 case YAHOO_STATUS_INVISIBLE:
455 st = invisible;
456 break;
457 case -1:
458 st = offline;
459 break;
462 return st;
465 bool yahoohook::enabled() const {
466 return true;
469 void yahoohook::setautostatus(imstatus st) {
470 if(st == offline) {
471 if(getstatus() != offline) {
472 disconnect();
474 } else {
475 if(getstatus() == offline) {
476 connect();
478 } else {
479 logger.putourstatus(proto, getstatus(), ourstatus = st);
481 if(st == freeforchat) {
482 /* TODO copy should not be needed here ?*/
483 char *msg = strdup("free for chat");
484 yahoo_set_away(cid, (yahoo_status) stat2int[st], msg, 0);
485 free (msg);
487 } else if(st != away) {
488 yahoo_set_away(cid, (yahoo_status) stat2int[st], 0, 0);
490 } else {
491 char *msg = strdup(rusconv("ku", conf->getawaymsg(proto)).c_str());
492 yahoo_set_away(cid, (yahoo_status) stat2int[st], msg, 1);
493 free (msg);
500 imstatus yahoohook::getstatus() const {
501 return online() ? ourstatus : offline;
504 void yahoohook::requestinfo(const imcontact &ic) {
505 requestfromfound(ic);
507 icqcontact *c = clist.get(ic);
508 if(!c) c = clist.get(contactroot);
510 icqcontact::moreinfo m = c->getmoreinfo();
511 icqcontact::basicinfo b = c->getbasicinfo();
513 m.homepage = "http://profiles.yahoo.com/" + ic.nickname;
514 b.email = ic.nickname + "@yahoo.com";
516 c->setmoreinfo(m);
517 c->setbasicinfo(b);
520 void yahoohook::userstatus(const string &nick, int st, const string &message, bool away) {
521 imcontact ic(nick, proto);
522 icqcontact *c = clist.get(ic);
524 awaymessages[nick] = rusconv("wk", message);
526 if(!c) {
527 c = clist.addnew(ic, false);
530 if(c) {
531 logger.putonline(ic, c->getstatus(), yahoo2imstatus(st));
532 c->setstatus(yahoo2imstatus(st));
536 YList *yahoohook::getmembers(const string &room) {
537 int i;
538 static YList *smemb = 0;
539 vector<string>::iterator ic;
540 map<string, vector<string> >::iterator im;
542 if(smemb) {
543 for(YList *n = smemb; n; n = y_list_next(n))
544 free(n->data);
546 y_list_free(smemb);
547 smemb = 0;
550 if((im = confmembers.find(room)) != confmembers.end())
551 for(ic = im->second.begin(); ic != im->second.end(); ++ic)
552 smemb = y_list_append(smemb, strdup(ic->c_str()));
554 return smemb;
557 string yahoohook::decode(string text, bool utf) {
558 int npos, mpos;
560 text = rushtmlconv(utf ? "uk" : "wk", text);
562 while((npos = text.find("\e[")) != -1) {
563 if((mpos = text.substr(npos).find("m")) == -1)
564 mpos = text.size()-npos-1;
566 text.erase(npos, mpos+1);
569 return text;
572 bool yahoohook::knowntransfer(const imfile &fr) const {
573 return fvalid.find(fr) != fvalid.end();
576 void yahoohook::replytransfer(const imfile &fr, bool accept, const string &localpath) {
577 if(accept) {
578 string localname = localpath + "/";
579 localname += fr.getfiles()[0].fname;
580 sfiles.push_back(strdup(localname.c_str()));
581 srfiles[sfiles.back()] = fr;
582 yahoo_get_url_handle(cid, fvalid[fr].c_str(), &get_url, sfiles.back());
584 } else {
585 fvalid.erase(fr);
590 void yahoohook::aborttransfer(const imfile &fr) {
591 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsCancel, 0, 0);
592 fvalid.erase(fr);
595 void yahoohook::lookup(const imsearchparams &params, verticalmenu &dest) {
596 string room;
597 icqcontact *c;
598 vector<string>::const_iterator i;
600 while(!foundguys.empty()) {
601 delete foundguys.back();
602 foundguys.pop_back();
605 yahoo_search_gender gender = YAHOO_GENDER_NONE;
607 switch(params.gender) {
608 case genderMale: gender = YAHOO_GENDER_MALE; break;
609 case genderFemale: gender = YAHOO_GENDER_FEMALE; break;
612 searchonlineonly = params.onlineonly;
613 searchdest = &dest;
615 if(!params.kwords.empty()) {
616 yahoo_search(cid, YAHOO_SEARCH_KEYWORD, decode(params.kwords, false).c_str(),
617 gender, YAHOO_AGERANGE_NONE, params.photo ? 1 : 0, 1);
619 } else if(!params.firstname.empty()) {
620 yahoo_search(cid, YAHOO_SEARCH_NAME, decode(params.firstname, false).c_str(),
621 gender, YAHOO_AGERANGE_NONE, params.photo ? 1 : 0, 1);
623 } else if(!params.room.empty()) {
624 room = params.room.substr(1);
625 i = confmembers[room].begin();
627 while(i != confmembers[room].end()) {
628 if(c = clist.get(imcontact(*i, proto)))
629 searchdest->additem(conf->getcolor(cp_clist_yahoo),
630 c, (string) " " + *i);
632 ++i;
635 face.findready();
636 log(logConfMembers, searchdest->getcount());
638 searchdest->redraw();
639 searchdest = 0;
644 void yahoohook::conferencecreate(const imcontact &confid, const vector<imcontact> &lst) {
645 int i;
646 string room = confid.nickname.substr(1);
648 YList *who = 0;
650 vector<imcontact>::const_iterator il = lst.begin();
651 while(il != lst.end()) {
652 who = y_list_append(who, strdup(il->nickname.c_str()));
653 ++il;
656 yahoo_conference_invite(cid, 0, who, room.c_str(), _("Please join my conference."));
658 for(YList *w = who; w; w = y_list_next(w))
659 free(w->data);
661 y_list_free(who);
664 void yahoohook::requestawaymsg(const imcontact &ic) {
665 icqcontact *c = clist.get(ic);
667 if(c) {
668 if(awaymessages.find(ic.nickname) != awaymessages.end()) {
669 em.store(imnotification(ic, string() + _("Custom status message:") + "\n\n" +
670 awaymessages[ic.nickname]));
672 } else {
673 face.log(_("+ [yahoo] cannot fetch away msg from %s, %s (maybe no away msg set)"),
674 c->getdispnick().c_str(), ic.totext().c_str());
680 void yahoohook::checkinlist(imcontact ic) {
681 bool found = false;
682 icqcontact *c = clist.get(ic);
684 if(c)
685 if(c->inlist()) {
686 const YList *buddies = yahoo_get_buddylist(cid);
688 for(const YList *bud = buddies; bud && !found; ) {
689 yahoo_buddy *yb = (yahoo_buddy *) bud->data;
690 found = (c->getdesc().nickname == yb->id);
691 bud = y_list_next(bud);
694 if(!found) sendnewuser(ic, false);
698 void yahoohook::updatecontact(icqcontact *c) {
699 if(logged() && conf->getgroupmode() != icqconf::nogroups) {
700 bool found = false;
701 const YList *buddies = yahoo_get_buddylist(cid);
702 string newgroupname = groups.getname(c->getgroupid());
704 for(const YList *bud = buddies; bud; ) {
705 yahoo_buddy *yb = (yahoo_buddy *) bud->data;
707 if(c->getdesc().nickname == yb->id) {
708 if(!found) {
709 if(newgroupname != yb->group)
710 yahoo_change_buddy_group(cid, yb->id, yb->group, newgroupname.c_str());
712 found = true;
713 } else {
714 yahoo_remove_buddy(cid, yb->id, yb->group);
718 bud = y_list_next(bud);
723 void yahoohook::renamegroup(const string &oldname, const string &newname) {
724 if(logged()) {
725 string tempname = oldname + "___" + i2str(getpid()) + "_temp";
726 yahoo_group_rename(cid, oldname.c_str(), tempname.c_str());
727 yahoo_group_rename(cid, tempname.c_str(), newname.c_str());
731 // ----------------------------------------------------------------------------
733 void yahoohook::login_response(int id, int succ, char *url) {
734 vector<string>::iterator in;
736 switch(succ) {
737 case YAHOO_LOGIN_OK:
738 yhook.flogged = true;
739 logger.putourstatus(yahoo, offline, yhook.ourstatus = yhook.manualstatus);
740 yhook.log(logLogged);
741 time(&yhook.timer_refresh);
742 yhook.setautostatus(yhook.manualstatus);
743 yhook.timer_close = 0;
744 break;
746 case YAHOO_LOGIN_LOGOFF:
747 yhook.fonline = yhook.fonline = false;
748 yahoo_close(yhook.cid);
749 face.log(_("+ [yahoo] cannot login"));
750 break;
752 case YAHOO_LOGIN_PASSWD:
753 yhook.fonline = yhook.fonline = false;
754 yahoo_close(yhook.cid);
755 face.log(_("+ [yahoo] cannot login: username and password mismatch"));
756 break;
758 case YAHOO_LOGIN_UNAME:
759 yhook.fonline = yhook.fonline = false;
760 yahoo_close(yhook.cid);
761 face.log(_("+ [yahoo] cannot login: username doesn't exist"));
762 break;
764 case YAHOO_LOGIN_LOCK:
765 yhook.fonline = yhook.fonline = false;
766 yahoo_close(yhook.cid);
767 face.log(_("+ [yahoo] cannot login: the account has been blocked"));
768 face.log(_("+ to reactivate visit %s"), url);
769 break;
771 case YAHOO_LOGIN_DUPL:
772 face.log(_("+ [yahoo] another logon detected"));
773 yahoo_logoff(yhook.cid);
774 yhook.manualstatus = offline;
775 break;
777 case YAHOO_LOGIN_SOCK:
778 face.log(_("+ [yahoo] server closed socket"));
779 yhook.disconnected();
780 break;
783 face.update();
786 void yahoohook::got_buddies(int id, YList *buds) {
787 const YList *buddy;
789 for(buddy = buds; buddy; buddy = y_list_next(buddy)) {
790 yahoo_buddy *bud = static_cast<yahoo_buddy *>(buddy->data);
791 clist.updateEntry(imcontact(bud->id, yahoo), bud->group ? bud->group : "");
795 void yahoohook::got_identities(int id, YList *buds) {
798 void yahoohook::status_changed(int id, char *who, int stat, char *msg, int away, int idle, int mobile) {
799 yhook.userstatus(who, stat, msg ? msg : "", (bool) away);
802 void yahoohook::got_im(int id, char *me, char *who, char *msg, long tm, int stat, int utf8) {
803 imcontact ic(who, yahoo);
804 string text = cuthtml(msg, chCutBR | chLeaveLinks);
806 yhook.checkinlist(ic);
807 text = yhook.decode(text, utf8);
809 if(!text.empty()) {
810 em.store(immessage(ic, imevent::incoming, text, tm));
814 void yahoohook::got_search_result(int id, int found, int start, int total, YList *contacts) {
815 yahoo_found_contact *fc;
816 icqcontact *c;
817 YList *ir;
818 string sg, line;
820 if(!yhook.searchdest)
821 return;
823 for(ir = contacts; ir; ir = ir->next) {
824 fc = (yahoo_found_contact *) ir->data;
826 if(yhook.searchonlineonly && !fc->online)
827 continue;
829 c = new icqcontact(imcontact(fc->id, yahoo));
831 icqcontact::basicinfo binfo = c->getbasicinfo();
832 icqcontact::moreinfo minfo = c->getmoreinfo();
834 if(!fc->id || !fc->gender)
835 continue;
837 c->setnick(fc->id);
838 c->setdispnick(c->getnick());
840 sg = up(fc->gender);
841 if(sg == "MALE") minfo.gender = genderMale;
842 else if(sg == "FEMALE") minfo.gender = genderFemale;
844 minfo.age = fc->age;
845 if(fc->location) binfo.street = fc->location;
847 line = (fc->online ? "o " : " ") + c->getnick();
849 if(fc->age || fc->location || strlen(fc->gender) >= 4) {
850 line += " <";
851 if(fc->age) line += i2str(fc->age);
853 if(strlen(fc->gender) >= 4) {
854 if(fc->age) line += ", ";
855 line += fc->gender;
858 if(fc->location && strlen(fc->location)) {
859 if(fc->age || strlen(fc->gender) >= 4) line += ", ";
860 line += fc->location;
863 line += ">";
866 c->setbasicinfo(binfo);
867 c->setmoreinfo(minfo);
869 yhook.foundguys.push_back(c);
870 yhook.searchdest->additem(conf->getcolor(cp_clist_yahoo), c, line);
873 yhook.searchdest->redraw();
875 if(start + found >= total) {
876 face.findready();
877 yhook.log(logSearchFinished, yhook.foundguys.size());
878 yhook.searchdest = 0;
879 } else {
880 yahoo_search_again(yhook.cid, -1);
884 void yahoohook::got_conf_invite(int id, char *who, char *room, char *msg, YList *members) {
885 icqconf::imaccount acc = conf->getourid(yahoo);
886 string confname = (string) "#" + room, inviter, text;
887 vector<string>::iterator ic;
888 char buf[NOTIFBUF];
889 int i;
891 imcontact cont(confname, yahoo);
892 icqcontact *c = clist.get(cont);
893 if(!c) c = clist.addnew(cont);
895 inviter = confname.substr(1);
896 if((i = inviter.rfind("-")) != -1) {
897 inviter.erase(i);
900 snprintf(buf, NOTIFBUF, _("The user %s has invited you to the %s conference, the topic there is: %s"),
901 yhook.rusconv("wk", inviter).c_str(),
902 yhook.rusconv("wk", room).c_str(),
903 yhook.rusconv("wk", msg).c_str());
905 text = (string) buf + "\n\n" + _("Current conference members are: ");
906 yhook.confmembers[room].push_back(inviter);
908 for(YList *m = members; m; m = y_list_next(m)) {
909 string id = (char *) m->data;
911 if(id != acc.nickname)
912 if(find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), id) == yhook.confmembers[room].end()) {
913 yhook.confmembers[room].push_back(id);
917 for(ic = yhook.confmembers[room].begin(); ic != yhook.confmembers[room].end(); ) {
918 text += *ic;
919 if(++ic != yhook.confmembers[room].end())
920 text += ", ";
923 c->setstatus(available);
924 em.store(imnotification(cont, text));
925 em.store(imnotification(cont, _("Auto-joined the conference")));
927 yhook.tobedone.push_back(make_pair(tbdConfLogon, room));
930 void yahoohook::conf_userdecline(int id, char *who, char *room, char *msg) {
931 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
932 char buf[NOTIFBUF];
934 if(c) {
935 snprintf(buf, NOTIFBUF, _("The user %s has declined your invitation to join the conference"), who);
936 em.store(imnotification(c, buf));
940 void yahoohook::conf_userjoin(int id, char *who, char *room) {
941 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
942 char buf[NOTIFBUF];
944 if(c) {
945 snprintf(buf, NOTIFBUF, _("The user %s has joined the conference"), who);
947 if(find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), who) == yhook.confmembers[room].end())
948 yhook.confmembers[room].push_back(who);
950 em.store(imnotification(c, buf));
954 void yahoohook::conf_userleave(int id, char *who, char *room) {
955 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
956 char buf[NOTIFBUF];
957 vector<string>::iterator im;
959 if(c) {
960 snprintf(buf, NOTIFBUF, _("The user %s has left the conference"), who);
961 em.store(imnotification(c, buf));
963 im = find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), who);
964 if(im != yhook.confmembers[room].end()) yhook.confmembers[room].erase(im);
968 void yahoohook::conf_message(int id, char *who, char *room, char *msg, int utf8) {
969 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
971 string text = (string) who + ": " + cuthtml(msg, chCutBR | chLeaveLinks);
972 text = yhook.decode(text, utf8);
974 if(c) em.store(immessage(c, imevent::incoming, text));
977 void yahoohook::got_file(int id, char *me, char *who, char *url, long expires, char *msg, char *fname, unsigned long fesize) {
978 if(!who || !url)
979 return;
981 if(!fname) {
982 fname = strrchr(url, '/');
983 if(fname) fname++;
984 else return;
987 int pos;
988 imfile::record r;
989 r.fname = fname;
990 r.size = fesize;
991 if(!fesize) r.size = -1;
993 if((pos = r.fname.find('?')) != -1)
994 r.fname.erase(pos);
996 imfile fr(imcontact(who, yahoo), imevent::incoming, "",
997 vector<imfile::record>(1, r));
999 yhook.fvalid[fr] = url;
1000 em.store(fr);
1002 face.transferupdate(fname, fr, icqface::tsInit, fesize, 0);
1005 void yahoohook::contact_added(int id, char *myid, char *who, char *msg) {
1006 string text = _("The user has added you to his/her contact list");
1008 if(msg)
1009 if(strlen(msg)) {
1010 text += (string) ", " + _("the message was: ") + msg;
1013 em.store(imnotification(imcontact(who, yahoo), text));
1016 void yahoohook::typing_notify(int id, char *me, char *who, int stat) {
1017 icqcontact *c = clist.get(imcontact(who, yahoo));
1018 if(c) c->setlasttyping(stat ? timer_current : 0);
1021 void yahoohook::game_notify(int id, char *me, char *who, int stat) {
1024 void yahoohook::mail_notify(int id, char *from, char *subj, int cnt) {
1025 char buf[NOTIFBUF];
1027 if(from && subj) {
1028 snprintf(buf, NOTIFBUF, _("+ [yahoo] e-mail from %s, %s"), from, subj);
1029 face.log(buf);
1030 clist.get(contactroot)->playsound(imevent::email);
1034 void yahoohook::system_message(int id, char *msg) {
1035 face.log(_("+ [yahoo] system: %s"), msg);
1038 void yahoohook::error(int id, char *err, int fatal, int num) {
1039 if(fatal) {
1040 face.log(_("+ [yahoo] error: %s"), err);
1041 yhook.disconnected();
1045 int yahoohook::add_handler(int id, int fd, yahoo_input_condition cond, void *data) {
1046 int tag = -1;
1048 switch(cond) {
1049 case YAHOO_INPUT_READ:
1050 yhook.rfds.push_back(yfd(fd, data));
1051 tag = yhook.rfds.back().tag;
1052 break;
1053 case YAHOO_INPUT_WRITE:
1054 yhook.wfds.push_back(yfd(fd, data));
1055 tag = yhook.wfds.back().tag;
1056 break;
1059 return tag;
1062 void yahoohook::remove_handler(int id, int tag) {
1063 vector<yfd>::iterator i;
1065 i = find(yhook.rfds.begin(), yhook.rfds.end(), tag);
1066 if(i != yhook.rfds.end())
1067 yhook.rfds.erase(i);
1069 i = find(yhook.wfds.begin(), yhook.wfds.end(), tag);
1070 if(i != yhook.wfds.end())
1071 yhook.wfds.erase(i);
1074 int yahoohook::connect_async(int id, char *host, int port, yahoo_connect_callback callback, void *data) {
1075 struct sockaddr_in serv_addr;
1076 static struct hostent *server;
1077 int servfd;
1078 struct connect_callback_data * ccd;
1079 int error;
1081 if(!(server = gethostbyname(host))) {
1082 errno = h_errno;
1083 return -1;
1086 if((servfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1087 return -1;
1090 memset(&serv_addr, 0, sizeof(serv_addr));
1091 serv_addr.sin_family = AF_INET;
1092 memcpy(&serv_addr.sin_addr.s_addr, *server->h_addr_list, server->h_length);
1093 serv_addr.sin_port = htons(port);
1095 int f = fcntl(servfd, F_GETFL);
1096 fcntl(servfd, F_SETFL, f | O_NONBLOCK);
1098 error = cw_connect(servfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr), 0);
1100 if(!error) {
1101 callback(servfd, 0, data);
1102 return 0;
1103 } else if(error == -1 && errno == EINPROGRESS) {
1104 ccd = new connect_callback_data;
1105 ccd->callback = callback;
1106 ccd->callback_data = data;
1107 ccd->id = id;
1109 yhook.wfds.push_back(yfd(servfd, ccd, true));
1110 ccd->tag = yhook.wfds.back().tag;
1111 return 1;
1112 } else {
1113 close(servfd);
1114 return -1;
1118 void yahoohook::connect_complete(void *data, int source) {
1119 connect_callback_data *ccd = (connect_callback_data *) data;
1120 int so_error;
1121 socklen_t err_size = sizeof(so_error);
1123 remove_handler(0, ccd->tag);
1125 if(getsockopt(source, SOL_SOCKET, SO_ERROR, (char *) &so_error, &err_size) == -1 || so_error != 0) {
1126 if(yhook.logged())
1127 face.log(_("+ [yahoo] direct connection failed"));
1129 close(source);
1130 source = -1;
1131 } else {
1132 ccd->callback(source, so_error, ccd->callback_data);
1135 delete ccd;
1138 void yahoohook::got_ignore(int id, YList * igns) {
1141 void yahoohook::got_cookies(int id) {
1144 void yahoohook::chat_cat_xml(int id, char *xml) {
1147 void yahoohook::chat_join(int id, char *room, char *topic, YList *members, int fd) {
1150 void yahoohook::chat_userjoin(int id, char *room, struct yahoo_chat_member *who) {
1153 void yahoohook::chat_userleave(int id, char *room, char *who) {
1156 void yahoohook::chat_message(int id, char *who, char *room, char *msg, int msgtype, int utf8) {
1159 void yahoohook::rejected(int id, char *who, char *msg) {
1162 void yahoohook::got_webcam_image(int id, const char * who, const unsigned char *image, unsigned int image_size, unsigned int real_size, unsigned int timestamp) {
1165 void yahoohook::webcam_invite(int id, char *me, char *from) {
1168 void yahoohook::webcam_invite_reply(int id, char *me, char *from, int accept) {
1171 void yahoohook::webcam_closed(int id, char *who, int reason) {
1174 void yahoohook::webcam_viewer(int id, char *who, int connect) {
1177 void yahoohook::webcam_data_request(int id, int send) {
1180 void yahoohook::auth_request(int id, char *who, char *msg) {
1181 imcontact ic(who, yahoo);
1182 string text = cuthtml(msg?msg: "", chCutBR | chLeaveLinks);
1184 yhook.checkinlist(ic);
1185 text = yhook.decode(text, true);
1187 em.store(imauthorization(ic, imevent::incoming, imauthorization::Request, text));
1190 void yahoohook::auth_response(int id, const char *who, char granted, const char *msg) {
1191 imcontact ic(who, yahoo);
1192 string text = cuthtml(msg?msg:"", chCutBR | chLeaveLinks);
1194 //yhook.checkinlist(ic);
1195 text = yhook.decode(text, true);
1196 string message;
1197 if (granted)
1198 message = "The user has accepted your authorization request";
1199 else
1201 message = "The user has rejected your authorization request";
1202 if (!text.empty())
1204 message += " (";
1205 message += text;
1206 message += ")";
1210 em.store(imnotification(ic, message));
1213 int yahoohook::ylog(char *fmt, ...) {
1214 if(conf->getdebug()) {
1215 char buf[NOTIFBUF];
1216 va_list ap;
1218 va_start(ap, fmt);
1219 vsnprintf(buf, NOTIFBUF, fmt, ap);
1220 va_end(ap);
1222 face.log(buf);
1225 return 0;
1228 void yahoohook::get_fd(int id, int fd, int error, void *data) {
1229 const char *fname = (const char *) data;
1230 char buf[1024];
1231 int size = 0;
1233 if(!error) {
1234 ifstream f(fname);
1236 if(f.is_open()) {
1237 while(!f.eof()) {
1238 f.read(buf, 1024);
1239 write(fd, buf, f.tellg());
1240 size += f.tellg();
1242 f.close();
1246 map<const char *, imfile>::iterator ir = yhook.srfiles.find(fname);
1247 if(ir != yhook.srfiles.end()) {
1248 face.transferupdate(fname, ir->second,
1249 error ? icqface::tsError : icqface::tsFinish,
1250 size, size);
1252 yhook.srfiles.erase(ir);
1255 vector<char *>::iterator i = find(yhook.sfiles.begin(), yhook.sfiles.end(), fname);
1256 if(i != yhook.sfiles.end()) {
1257 delete *i;
1258 yhook.sfiles.erase(i);
1262 void yahoohook::get_url(int id, int fd, int error, const char *filename, unsigned long size, void *data) {
1263 int rsize = 0;
1264 const char *localname = (const char *) data;
1266 if(!error) {
1267 vector<char *>::iterator i = find(yhook.sfiles.begin(), yhook.sfiles.end(), localname);
1268 if(i != yhook.sfiles.end()) {
1269 ofstream f(localname);
1271 if(f.is_open()) {
1272 int r;
1273 char buf[1024];
1274 FILE *fp = fdopen(fd, "r");
1276 while(!feof(fp)) {
1277 r = fread(buf, 1, 1024, fp);
1278 if(r > 0) f.write(buf, r);
1279 rsize += r;
1282 fclose(fp);
1283 f.close();
1284 } else {
1285 error = -1;
1288 delete *i;
1289 yhook.sfiles.erase(i);
1293 map<const char *, imfile>::iterator ir = yhook.srfiles.find(localname);
1294 if(ir != yhook.srfiles.end()) {
1295 face.transferupdate(justfname(localname), ir->second,
1296 error ? icqface::tsError : icqface::tsFinish,
1297 size, rsize);
1299 yhook.srfiles.erase(ir);
1304 #endif