Yahoo - implement missing callback stubs
[centerim.git] / src / hooks / yahoohook.cc
blob61ad5f4dcf1d63dba2d88989305debc5367f57bf
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);
81 fcapabs.insert(hookcapab::ssl);
83 pager_host[0] = pager_port[0] = filetransfer_host[0] =
84 filetransfer_port[0] = webcam_host[0] = webcam_port[0] =
85 local_host[0] = 0;
88 yahoohook::~yahoohook() {
91 void yahoohook::init() {
92 manualstatus = conf->getstatus(proto);
94 static struct yahoo_callbacks c;
96 memset(&c, 0, sizeof(c));
98 c.ext_yahoo_login_response = &login_response;
99 c.ext_yahoo_got_buddies = &got_buddies;
100 c.ext_yahoo_status_changed = &status_changed;
101 c.ext_yahoo_got_im = &got_im;
102 c.ext_yahoo_got_conf_invite = &got_conf_invite;
103 c.ext_yahoo_conf_userdecline = &conf_userdecline;
104 c.ext_yahoo_conf_userjoin = &conf_userjoin;
105 c.ext_yahoo_conf_userleave = &conf_userleave;
106 c.ext_yahoo_conf_message = &conf_message;
107 c.ext_yahoo_got_file = &got_file;
108 c.ext_yahoo_contact_added = &contact_added;
109 c.ext_yahoo_game_notify = &game_notify;
110 c.ext_yahoo_mail_notify = &mail_notify;
111 c.ext_yahoo_system_message = &system_message;
112 c.ext_yahoo_error = &error;
113 c.ext_yahoo_add_handler = &add_handler;
114 c.ext_yahoo_remove_handler = &remove_handler;
115 c.ext_yahoo_connect_async = &connect_async;
116 c.ext_yahoo_read = &y_read;
117 c.ext_yahoo_write = &y_write;
118 c.ext_yahoo_close = &y_close;
119 c.ext_yahoo_got_identities = &got_identities;
120 c.ext_yahoo_got_ignore = &got_ignore;
121 c.ext_yahoo_got_cookies = &got_cookies;
122 c.ext_yahoo_chat_cat_xml = &chat_cat_xml;
123 c.ext_yahoo_chat_join = &chat_join;
124 c.ext_yahoo_chat_userjoin = &chat_userjoin;
125 c.ext_yahoo_chat_userleave = &chat_userleave;
126 c.ext_yahoo_chat_message = &chat_message;
127 c.ext_yahoo_rejected = &rejected;
128 c.ext_yahoo_typing_notify = &typing_notify;
129 c.ext_yahoo_got_webcam_image = &got_webcam_image;
130 c.ext_yahoo_webcam_invite = &webcam_invite;
131 c.ext_yahoo_webcam_invite_reply = &webcam_invite_reply;
132 c.ext_yahoo_webcam_closed = &webcam_closed;
133 c.ext_yahoo_webcam_viewer = &webcam_viewer;
134 c.ext_yahoo_webcam_data_request = &webcam_data_request;
135 c.ext_yahoo_got_search_result = &got_search_result;
136 c.ext_yahoo_got_ping = &got_ping;
137 c.ext_yahoo_log = &ylog;
138 c.ext_yahoo_got_buddyicon_request = &got_buddyicon_request;
139 c.ext_yahoo_got_buddyicon = &got_buddyicon;
140 c.ext_yahoo_buddyicon_uploaded = &buddyicon_uploaded;
141 c.ext_yahoo_chat_yahooerror = &chat_yahooerror;
142 c.ext_yahoo_chat_yahoologout = &chat_yahoologout;
143 c.ext_yahoo_connect = &yahoo_connect;
144 c.ext_yahoo_file_transfer_done = &file_transfer_done;
145 c.ext_yahoo_get_ip_addr = &get_ip_addr;
146 c.ext_yahoo_got_buddy_change_group = &got_buddy_change_group;
147 c.ext_yahoo_got_buddyicon_checksum = &got_buddyicon_checksum;
148 c.ext_yahoo_got_buzz = &got_buzz;
149 c.ext_yahoo_got_ft_data = &got_ft_data;
151 yahoo_register_callbacks(&c);
154 void yahoohook::connect() {
155 icqconf::imaccount acc = conf->getourid(proto);
156 int r;
158 log(logConnecting);
160 if(cid < 0) {
161 yahoo_logoff(cid);
162 yahoo_close(cid);
165 cid = yahoo_init_with_attributes(acc.nickname.c_str(), acc.password.c_str(),
166 "pager_host", acc.server.c_str(),
167 "pager_port", acc.port,
168 (char *) NULL);
170 yahoo_login(cid, stat2int[manualstatus]);
172 if(cid < 0) {
173 string msg = _("+ [yahoo] cannot connect: ");
175 switch(cid) {
176 case -1: msg += _("could not resolve hostname"); break;
177 case -2: msg += _("could not create socket"); break;
178 default: msg += _("verify the pager host and port entered"); break;
181 face.log(msg);
182 } else {
183 fonline = true;
184 flogged = false;
188 void yahoohook::main() {
189 vector<yfd>::iterator i;
190 struct timeval tv;
191 int hsock;
192 fd_set rs, ws, es;
194 FD_ZERO(&rs);
195 FD_ZERO(&ws);
196 FD_ZERO(&es);
198 tv.tv_sec = tv.tv_usec = 0;
199 hsock = 0;
201 for(i = fds.begin(); i != fds.end(); ++i) {
202 struct y_c ic = i->con;
203 if (i->cond & YAHOO_INPUT_READ)
204 FD_SET(ic.fd, &rs);
205 if (i->cond & YAHOO_INPUT_WRITE)
206 FD_SET(ic.fd, &ws);
207 hsock = max(hsock, ic.fd);
210 if(select(hsock+1, &rs, &ws, 0, &tv) > 0) {
211 for(i = fds.begin(); i != fds.end(); ++i) {
212 if(i->isconnect) {
213 if (!cw_nb_connect(i->con.fd, NULL, 0, i->con.ssl, &i->con.state))
215 if (i->con.state & CW_CONNECT_WANT_SOMETHING)
216 continue;
218 else
220 cw_close(i->con.fd);
221 break;
223 struct y_c tc = i->con;
224 connect_complete(i->data, &tc);
225 break;
228 if(FD_ISSET(i->con.fd, &rs)) {
229 yahoo_read_ready(cid, &i->con, i->data);
230 break;
232 if(FD_ISSET(i->con.fd, &ws)) {
233 yahoo_write_ready(cid, &i->con, i->data);
234 break;
240 void yahoohook::getsockets(fd_set &rs, fd_set &ws, fd_set &es, int &hsocket) const {
241 if(online()) {
242 vector<yfd>::const_iterator i;
244 for(i = fds.begin(); i != fds.end(); ++i) {
245 if (i->cond & YAHOO_INPUT_READ)
246 FD_SET(i->con.fd, &rs);
247 if (i->cond & YAHOO_INPUT_WRITE)
248 FD_SET(i->con.fd, &ws);
249 hsocket = max(hsocket, i->con.fd);
254 bool yahoohook::isoursocket(fd_set &rs, fd_set &ws, fd_set &es) const {
255 vector<yfd>::const_iterator i;
257 for(i = fds.begin(); i != fds.end(); ++i)
259 if(i->cond & YAHOO_INPUT_READ && FD_ISSET(i->con.fd, &rs))
260 return true;
262 if(i->cond & YAHOO_INPUT_WRITE && FD_ISSET(i->con.fd, &ws))
263 return true;
265 return false;
268 void yahoohook::disconnect() {
269 if(online()) {
270 yahoo_logoff(cid);
271 time(&timer_close);
275 void yahoohook::disconnected() {
276 if(logged()) {
277 vector<yfd>::const_iterator i;
278 for(i = fds.begin(); i != fds.end(); ++i)
280 cw_close(i->con.fd);
283 fds.clear();
285 logger.putourstatus(proto, getstatus(), ourstatus = offline);
286 clist.setoffline(proto);
287 fonline = false;
288 log(logDisconnected);
289 face.update();
293 void yahoohook::exectimers() {
294 vector<pair<Action, string> >::iterator it;
296 for(it = tobedone.begin(); it != tobedone.end(); ++it) {
297 switch(it->first) {
298 case tbdConfLogon:
299 /* TODO: investigate if copy is really needed here */
300 char *room = strdup(it->second.c_str());
301 yahoo_conference_logon(cid, 0, getmembers(it->second), room);
302 free (room);
303 break;
307 tobedone.clear();
309 if(logged()) {
310 if(timer_current-timer_refresh > PERIOD_REFRESH) {
311 yahoo_refresh(cid);
312 yahoo_keepalive(cid);
313 timer_refresh = timer_current;
315 } else if(timer_close && timer_current-timer_close > PERIOD_CLOSE) {
316 yahoo_close(cid);
317 disconnected();
323 struct tm *yahoohook::timestamp() {
324 return localtime(&timer_current);
327 bool yahoohook::send(const imevent &ev) {
328 icqcontact *c = clist.get(ev.getcontact());
329 string text;
331 if(c) {
332 if(ev.gettype() == imevent::message) {
333 const immessage *m = static_cast<const immessage *>(&ev);
334 if(m) text = rushtmlconv("ku", m->gettext());
336 } else if(ev.gettype() == imevent::url) {
337 const imurl *m = static_cast<const imurl *>(&ev);
338 if(m) text = rushtmlconv("ku", m->geturl()) + "\n\n" + rusconv("kw", m->getdescription());
340 } else if(ev.gettype() == imevent::file) {
341 const imfile *m = static_cast<const imfile *>(&ev);
342 vector<imfile::record> files = m->getfiles();
343 vector<imfile::record>::const_iterator ir;
345 for(ir = files.begin(); ir != files.end(); ++ir) {
346 sfiles.push_back(strdup(ir->fname.c_str()));
347 srfiles[sfiles.back()] = *m;
349 yahoo_send_file(cid, ev.getcontact().nickname.c_str(),
350 m->getmessage().c_str(), justfname(ir->fname).c_str(),
351 ir->size, &get_fd, sfiles.back());
354 return true;
355 } else if (ev.gettype() == imevent::authorization) {
356 const imauthorization *m = static_cast<const imauthorization *> (&ev);
358 switch(m->getauthtype()) {
359 case imauthorization::Granted:
360 yahoo_confirm_buddy(cid, ev.getcontact().nickname.c_str(), 0, 0);
361 break;
363 case imauthorization::Rejected:
364 yahoo_confirm_buddy(cid, ev.getcontact().nickname.c_str(), 1, 0);
365 break;
368 return true;
371 if(!ischannel(c)) {
372 yahoo_send_im(cid, 0, ev.getcontact().nickname.c_str(), text.c_str(), 0, 0);
373 } else {
374 yahoo_conference_message(cid, 0, getmembers(ev.getcontact().nickname.substr(1)),
375 ev.getcontact().nickname.c_str()+1, text.c_str(), 0);
378 return true;
381 return false;
384 bool yahoohook::online() const {
385 return fonline;
388 bool yahoohook::logged() const {
389 return fonline && flogged;
392 bool yahoohook::isconnecting() const {
393 return fonline && !flogged;
396 void yahoohook::sendnewuser(const imcontact &ic) {
397 sendnewuser(ic, true);
400 void yahoohook::sendnewuser(const imcontact &ic, bool report) {
401 if(online() && !ischannel(ic)) {
402 if(logged()) {
403 bool found = false;
404 const YList *buddies = yahoo_get_buddylist(cid);
405 const YList *bud = 0;
407 for(bud = buddies; bud && !found; bud = y_list_next(bud))
408 found = ic.nickname == static_cast<yahoo_buddy *>(bud->data)->id;
410 if(!found) {
411 if(report) log(logContactAdd, ic.nickname.c_str());
412 if (groups.size()>0)
414 vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), clist.get(ic)->getgroupid());
415 if (ig == groups.end())
416 ig = groups.begin();
417 yahoo_add_buddy(cid, ic.nickname.c_str(), ig->getname().c_str(), "");
423 requestinfo(ic);
426 void yahoohook::removeuser(const imcontact &ic) {
427 removeuser(ic, true);
430 void yahoohook::removeuser(const imcontact &ic, bool report) {
431 if(logged()) {
432 if(!ischannel(ic)) {
433 if(report) log(logContactRemove, ic.nickname.c_str());
435 const YList *buddies = yahoo_get_buddylist(cid);
436 const YList *bud = 0;
438 for(bud = buddies; bud; bud = y_list_next(bud)) {
439 if(ic.nickname == ((yahoo_buddy *) bud->data)->id)
440 yahoo_remove_buddy(cid,
441 ((yahoo_buddy *) bud->data)->id,
442 ((yahoo_buddy *) bud->data)->group);
444 } else {
445 if(report)
446 face.log(_("+ [yahoo] leaving the %s conference"),
447 ic.nickname.c_str());
449 yahoo_conference_logoff(cid, 0, getmembers(ic.nickname.substr(1)), ic.nickname.c_str()+1);
454 imstatus yahoohook::yahoo2imstatus(int status) {
455 imstatus st = offline;
457 switch(status) {
458 case YAHOO_STATUS_AVAILABLE:
459 st = available;
460 break;
461 case YAHOO_STATUS_BUSY:
462 st = dontdisturb;
463 break;
464 case YAHOO_STATUS_CUSTOM:
465 case YAHOO_STATUS_BRB:
466 case YAHOO_STATUS_IDLE:
467 case YAHOO_STATUS_ONPHONE:
468 st = away;
469 break;
470 case YAHOO_STATUS_NOTATDESK:
471 st = occupied;
472 break;
473 case YAHOO_STATUS_NOTATHOME:
474 case YAHOO_STATUS_NOTINOFFICE:
475 case YAHOO_STATUS_ONVACATION:
476 case YAHOO_STATUS_STEPPEDOUT:
477 st = notavail;
478 break;
479 case YAHOO_STATUS_OUTTOLUNCH:
480 st = outforlunch;
481 break;
482 case YAHOO_STATUS_INVISIBLE:
483 st = invisible;
484 break;
485 case -1:
486 st = offline;
487 break;
490 return st;
493 bool yahoohook::enabled() const {
494 return true;
497 void yahoohook::setautostatus(imstatus st) {
498 if(st == offline) {
499 if(getstatus() != offline) {
500 disconnect();
502 } else {
503 if(getstatus() == offline) {
504 connect();
506 } else {
507 logger.putourstatus(proto, getstatus(), ourstatus = st);
509 if(st == freeforchat) {
510 /* TODO copy should not be needed here ?*/
511 char *msg = strdup("free for chat");
512 yahoo_set_away(cid, (yahoo_status) stat2int[st], msg, 0);
513 free (msg);
515 } else if(st != away) {
516 yahoo_set_away(cid, (yahoo_status) stat2int[st], 0, 0);
518 } else {
519 char *msg = strdup(rusconv("ku", conf->getawaymsg(proto)).c_str());
520 yahoo_set_away(cid, (yahoo_status) stat2int[st], msg, 1);
521 free (msg);
528 imstatus yahoohook::getstatus() const {
529 return online() ? ourstatus : offline;
532 void yahoohook::requestinfo(const imcontact &ic) {
533 requestfromfound(ic);
535 icqcontact *c = clist.get(ic);
536 if(!c) c = clist.get(contactroot);
538 icqcontact::moreinfo m = c->getmoreinfo();
539 icqcontact::basicinfo b = c->getbasicinfo();
541 m.homepage = "http://profiles.yahoo.com/" + ic.nickname;
542 b.email = ic.nickname + "@yahoo.com";
544 c->setmoreinfo(m);
545 c->setbasicinfo(b);
548 void yahoohook::userstatus(const string &nick, int st, const string &message, bool away) {
549 imcontact ic(nick, proto);
550 icqcontact *c = clist.get(ic);
552 awaymessages[nick] = rusconv("wk", message);
554 if(!c) {
555 c = clist.addnew(ic, false);
558 if(c) {
559 logger.putonline(ic, c->getstatus(), yahoo2imstatus(st));
560 c->setstatus(yahoo2imstatus(st));
564 YList *yahoohook::getmembers(const string &room) {
565 int i;
566 static YList *smemb = 0;
567 vector<string>::iterator ic;
568 map<string, vector<string> >::iterator im;
570 if(smemb) {
571 for(YList *n = smemb; n; n = y_list_next(n))
572 free(n->data);
574 y_list_free(smemb);
575 smemb = 0;
578 if((im = confmembers.find(room)) != confmembers.end())
579 for(ic = im->second.begin(); ic != im->second.end(); ++ic)
580 smemb = y_list_append(smemb, strdup(ic->c_str()));
582 return smemb;
585 string yahoohook::decode(string text, bool utf) {
586 int npos, mpos;
588 text = rushtmlconv(utf ? "uk" : "wk", text);
590 while((npos = text.find("\e[")) != -1) {
591 if((mpos = text.substr(npos).find("m")) == -1)
592 mpos = text.size()-npos-1;
594 text.erase(npos, mpos+1);
597 return text;
600 bool yahoohook::knowntransfer(const imfile &fr) const {
601 return fvalid.find(fr) != fvalid.end();
604 void yahoohook::replytransfer(const imfile &fr, bool accept, const string &localpath) {
605 /* if(accept) {
606 string localname = localpath + "/";
607 localname += fr.getfiles()[0].fname;
608 sfiles.push_back(strdup(localname.c_str()));
609 srfiles[sfiles.back()] = fr;
610 yahoo_get_url_handle(cid, fvalid[fr].c_str(), &get_url, sfiles.back());
612 } else {
613 fvalid.erase(fr);
618 void yahoohook::aborttransfer(const imfile &fr) {
619 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsCancel, 0, 0);
620 fvalid.erase(fr);
623 void yahoohook::lookup(const imsearchparams &params, verticalmenu &dest) {
624 string room;
625 icqcontact *c;
626 vector<string>::const_iterator i;
628 while(!foundguys.empty()) {
629 delete foundguys.back();
630 foundguys.pop_back();
633 yahoo_search_gender gender = YAHOO_GENDER_NONE;
635 switch(params.gender) {
636 case genderMale: gender = YAHOO_GENDER_MALE; break;
637 case genderFemale: gender = YAHOO_GENDER_FEMALE; break;
640 searchonlineonly = params.onlineonly;
641 searchdest = &dest;
643 if(!params.kwords.empty()) {
644 yahoo_search(cid, YAHOO_SEARCH_KEYWORD, decode(params.kwords, false).c_str(),
645 gender, YAHOO_AGERANGE_NONE, params.photo ? 1 : 0, 1);
647 } else if(!params.firstname.empty()) {
648 yahoo_search(cid, YAHOO_SEARCH_NAME, decode(params.firstname, false).c_str(),
649 gender, YAHOO_AGERANGE_NONE, params.photo ? 1 : 0, 1);
651 } else if(!params.room.empty()) {
652 room = params.room.substr(1);
653 i = confmembers[room].begin();
655 while(i != confmembers[room].end()) {
656 if(c = clist.get(imcontact(*i, proto)))
657 searchdest->additem(conf->getcolor(cp_clist_yahoo),
658 c, (string) " " + *i);
660 ++i;
663 face.findready();
664 log(logConfMembers, searchdest->getcount());
666 searchdest->redraw();
667 searchdest = 0;
672 void yahoohook::conferencecreate(const imcontact &confid, const vector<imcontact> &lst) {
673 int i;
674 string room = confid.nickname.substr(1);
676 YList *who = 0;
678 vector<imcontact>::const_iterator il = lst.begin();
679 while(il != lst.end()) {
680 who = y_list_append(who, strdup(il->nickname.c_str()));
681 ++il;
684 yahoo_conference_invite(cid, 0, who, room.c_str(), _("Please join my conference."));
686 for(YList *w = who; w; w = y_list_next(w))
687 free(w->data);
689 y_list_free(who);
692 void yahoohook::requestawaymsg(const imcontact &ic) {
693 icqcontact *c = clist.get(ic);
695 if(c) {
696 if(awaymessages.find(ic.nickname) != awaymessages.end()) {
697 em.store(imnotification(ic, string() + _("Custom status message:") + "\n\n" +
698 awaymessages[ic.nickname]));
700 } else {
701 face.log(_("+ [yahoo] cannot fetch away msg from %s, %s (maybe no away msg set)"),
702 c->getdispnick().c_str(), ic.totext().c_str());
708 void yahoohook::checkinlist(imcontact ic) {
709 bool found = false;
710 icqcontact *c = clist.get(ic);
712 if(c)
713 if(c->inlist()) {
714 const YList *buddies = yahoo_get_buddylist(cid);
716 for(const YList *bud = buddies; bud && !found; ) {
717 yahoo_buddy *yb = (yahoo_buddy *) bud->data;
718 found = (c->getdesc().nickname == yb->id);
719 bud = y_list_next(bud);
722 if(!found) sendnewuser(ic, false);
726 void yahoohook::updatecontact(icqcontact *c) {
727 if(logged() && conf->getgroupmode() != icqconf::nogroups) {
728 bool found = false;
729 const YList *buddies = yahoo_get_buddylist(cid);
730 string newgroupname = groups.getname(c->getgroupid());
732 for(const YList *bud = buddies; bud; ) {
733 yahoo_buddy *yb = (yahoo_buddy *) bud->data;
735 if(c->getdesc().nickname == yb->id) {
736 if(!found) {
737 if(newgroupname != yb->group)
738 yahoo_change_buddy_group(cid, yb->id, yb->group, newgroupname.c_str());
740 found = true;
741 } else {
742 yahoo_remove_buddy(cid, yb->id, yb->group);
746 bud = y_list_next(bud);
751 void yahoohook::renamegroup(const string &oldname, const string &newname) {
752 if(logged()) {
753 string tempname = oldname + "___" + i2str(getpid()) + "_temp";
754 yahoo_group_rename(cid, oldname.c_str(), tempname.c_str());
755 yahoo_group_rename(cid, tempname.c_str(), newname.c_str());
759 // ----------------------------------------------------------------------------
761 void yahoohook::login_response(int id, int succ, const char *url) {
762 vector<string>::iterator in;
764 switch(succ) {
765 case YAHOO_LOGIN_OK:
766 yhook.flogged = true;
767 logger.putourstatus(yahoo, offline, yhook.ourstatus = yhook.manualstatus);
768 yhook.log(logLogged);
769 time(&yhook.timer_refresh);
770 yhook.setautostatus(yhook.manualstatus);
771 yhook.timer_close = 0;
772 break;
774 case YAHOO_LOGIN_LOGOFF:
775 yhook.fonline = yhook.fonline = false;
776 yahoo_close(yhook.cid);
777 face.log(_("+ [yahoo] cannot login"));
778 break;
780 case YAHOO_LOGIN_PASSWD:
781 yhook.fonline = yhook.fonline = false;
782 yahoo_close(yhook.cid);
783 face.log(_("+ [yahoo] cannot login: username and password mismatch"));
784 break;
786 case YAHOO_LOGIN_UNAME:
787 yhook.fonline = yhook.fonline = false;
788 yahoo_close(yhook.cid);
789 face.log(_("+ [yahoo] cannot login: username doesn't exist"));
790 break;
792 case YAHOO_LOGIN_LOCK:
793 yhook.fonline = yhook.fonline = false;
794 yahoo_close(yhook.cid);
795 face.log(_("+ [yahoo] cannot login: the account has been blocked"));
796 face.log(_("+ to reactivate visit %s"), url);
797 break;
799 case YAHOO_LOGIN_DUPL:
800 face.log(_("+ [yahoo] another logon detected"));
801 yahoo_logoff(yhook.cid);
802 yhook.manualstatus = offline;
803 break;
805 case YAHOO_LOGIN_UNKNOWN:
806 case YAHOO_LOGIN_SOCK:
807 face.log(_("+ [yahoo] server closed socket"));
808 yhook.disconnected();
809 break;
812 face.update();
815 void yahoohook::got_buddies(int id, YList *buds) {
816 const YList *buddy;
818 for(buddy = buds; buddy; buddy = y_list_next(buddy)) {
819 yahoo_buddy *bud = static_cast<yahoo_buddy *>(buddy->data);
821 clist.updateEntry(imcontact(bud->id, yahoo), bud->group ? bud->group : "");
825 void yahoohook::got_identities(int id, YList *buds) {
828 void yahoohook::status_changed(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile) {
829 yhook.userstatus(who, stat, msg ? msg : "", (bool) away);
832 void yahoohook::got_im(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8) {
833 imcontact ic(who, yahoo);
834 string text = cuthtml(msg, chCutBR | chLeaveLinks);
836 yhook.checkinlist(ic);
837 text = yhook.decode(text, utf8);
839 if(!text.empty()) {
840 em.store(immessage(ic, imevent::incoming, text, tm));
844 void yahoohook::got_search_result(int id, int found, int start, int total, YList *contacts) {
845 yahoo_found_contact *fc;
846 icqcontact *c;
847 YList *ir;
848 string sg, line;
850 if(!yhook.searchdest)
851 return;
853 for(ir = contacts; ir; ir = ir->next) {
854 fc = (yahoo_found_contact *) ir->data;
856 if(yhook.searchonlineonly && !fc->online)
857 continue;
859 c = new icqcontact(imcontact(fc->id, yahoo));
861 icqcontact::basicinfo binfo = c->getbasicinfo();
862 icqcontact::moreinfo minfo = c->getmoreinfo();
864 if(!fc->id || !fc->gender)
865 continue;
867 c->setnick(fc->id);
868 c->setdispnick(c->getnick());
870 sg = up(fc->gender);
871 if(sg == "MALE") minfo.gender = genderMale;
872 else if(sg == "FEMALE") minfo.gender = genderFemale;
874 minfo.age = fc->age;
875 if(fc->location) binfo.street = fc->location;
877 line = (fc->online ? "o " : " ") + c->getnick();
879 if(fc->age || fc->location || strlen(fc->gender) >= 4) {
880 line += " <";
881 if(fc->age) line += i2str(fc->age);
883 if(strlen(fc->gender) >= 4) {
884 if(fc->age) line += ", ";
885 line += fc->gender;
888 if(fc->location && strlen(fc->location)) {
889 if(fc->age || strlen(fc->gender) >= 4) line += ", ";
890 line += fc->location;
893 line += ">";
896 c->setbasicinfo(binfo);
897 c->setmoreinfo(minfo);
899 yhook.foundguys.push_back(c);
900 yhook.searchdest->additem(conf->getcolor(cp_clist_yahoo), c, line);
903 yhook.searchdest->redraw();
905 if(start + found >= total) {
906 face.findready();
907 yhook.log(logSearchFinished, yhook.foundguys.size());
908 yhook.searchdest = 0;
909 } else {
910 yahoo_search_again(yhook.cid, -1);
914 void yahoohook::got_conf_invite(int id, const char *me, const char *who, const char *room, const char *msg, YList *members) {
915 icqconf::imaccount acc = conf->getourid(yahoo);
916 string confname = (string) "#" + room, inviter, text;
917 vector<string>::iterator ic;
918 char buf[NOTIFBUF];
919 int i;
921 imcontact cont(confname, yahoo);
922 icqcontact *c = clist.get(cont);
923 if(!c) c = clist.addnew(cont);
925 inviter = confname.substr(1);
926 if((i = inviter.rfind("-")) != -1) {
927 inviter.erase(i);
930 snprintf(buf, NOTIFBUF, _("The user %s has invited you to the %s conference, the topic there is: %s"),
931 yhook.rusconv("wk", inviter).c_str(),
932 yhook.rusconv("wk", room).c_str(),
933 yhook.rusconv("wk", msg).c_str());
935 text = (string) buf + "\n\n" + _("Current conference members are: ");
936 yhook.confmembers[room].push_back(inviter);
938 for(YList *m = members; m; m = y_list_next(m)) {
939 string id = (char *) m->data;
941 if(id != acc.nickname)
942 if(find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), id) == yhook.confmembers[room].end()) {
943 yhook.confmembers[room].push_back(id);
947 for(ic = yhook.confmembers[room].begin(); ic != yhook.confmembers[room].end(); ) {
948 text += *ic;
949 if(++ic != yhook.confmembers[room].end())
950 text += ", ";
953 c->setstatus(available);
954 em.store(imnotification(cont, text));
955 em.store(imnotification(cont, _("Auto-joined the conference")));
957 yhook.tobedone.push_back(make_pair(tbdConfLogon, room));
960 void yahoohook::conf_userdecline(int id, const char *me, const char *who, const char *room, const char *msg) {
961 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
962 char buf[NOTIFBUF];
964 if(c) {
965 snprintf(buf, NOTIFBUF, _("The user %s has declined your invitation to join the conference"), who);
966 em.store(imnotification(c, buf));
970 void yahoohook::conf_userjoin(int id, const char *me, const char *who, const char *room) {
971 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
972 char buf[NOTIFBUF];
974 if(c) {
975 snprintf(buf, NOTIFBUF, _("The user %s has joined the conference"), who);
977 if(find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), who) == yhook.confmembers[room].end())
978 yhook.confmembers[room].push_back(who);
980 em.store(imnotification(c, buf));
984 void yahoohook::conf_userleave(int id, const char *me, const char *who, const char *room) {
985 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
986 char buf[NOTIFBUF];
987 vector<string>::iterator im;
989 if(c) {
990 snprintf(buf, NOTIFBUF, _("The user %s has left the conference"), who);
991 em.store(imnotification(c, buf));
993 im = find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), who);
994 if(im != yhook.confmembers[room].end()) yhook.confmembers[room].erase(im);
998 void yahoohook::conf_message(int id, const char *me, const char *who, const char *room, const char *msg, int utf8) {
999 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
1001 string text = (string) who + ": " + cuthtml(msg, chCutBR | chLeaveLinks);
1002 text = yhook.decode(text, utf8);
1004 if(c) em.store(immessage(c, imevent::incoming, text));
1007 void yahoohook::got_file(int id, const char *me, const char *who, const char *msg, const char *fname, unsigned long fesize, char *trid) {
1008 if(!who || !fname || !trid)
1009 return;
1011 int pos;
1012 imfile::record r;
1013 r.fname = fname;
1014 r.size = fesize;
1015 if(!fesize) r.size = -1;
1017 if((pos = r.fname.find('?')) != -1)
1018 r.fname.erase(pos);
1020 imfile fr(imcontact(who, yahoo), imevent::incoming, "",
1021 vector<imfile::record>(1, r));
1023 yhook.fvalid[fr] = trid;
1024 em.store(fr);
1026 face.transferupdate(fname, fr, icqface::tsInit, fesize, 0);
1029 void yahoohook::contact_added(int id, const char *myid, const char *who, const char *msg) {
1030 string text = _("The user has added you to his/her contact list");
1032 if(msg)
1033 if(strlen(msg)) {
1034 text += (string) ", " + _("the message was: ") + msg;
1037 em.store(imnotification(imcontact(who, yahoo), text));
1040 void yahoohook::typing_notify(int id, const char *me, const char *who, int stat) {
1041 icqcontact *c = clist.get(imcontact(who, yahoo));
1042 if(c) c->setlasttyping(stat ? timer_current : 0);
1045 void yahoohook::game_notify(int id, const char *me, const char *who, int stat, const char *msg) {
1048 void yahoohook::mail_notify(int id, const char *from, const char *subj, int cnt) {
1049 char buf[NOTIFBUF];
1051 if(from && subj) {
1052 snprintf(buf, NOTIFBUF, _("+ [yahoo] e-mail from %s, %s"), from, subj);
1053 face.log(buf);
1054 clist.get(contactroot)->playsound(imevent::email);
1058 void yahoohook::system_message(int id, const char *me, const char *who, const char *msg) {
1059 face.log(_("+ [yahoo] system (%s): %s"), who, msg);
1062 void yahoohook::got_ping(int id, const char *msg) {
1063 // face.log(_("+ [yahoo] ping: %s"), msg);
1066 void yahoohook::error(int id, const char *err, int fatal, int num) {
1067 if(fatal) {
1068 face.log(_("+ [yahoo] fatal error: %s"), err);
1069 yhook.disconnected();
1071 else {
1072 face.log(_("[yahoo] error %s"), err);
1076 int yahoohook::add_handler(int id, void *fd, yahoo_input_condition cond, void *data) {
1077 int tag = -1;
1078 struct y_c *con = (struct y_c *)fd;
1080 yhook.fds.push_back(yfd(con->fd, data, con->ssl, cond));
1081 tag = yhook.fds.back().tag;
1083 return tag;
1086 void yahoohook::remove_handler(int id, int tag) {
1087 vector<yfd>::iterator i;
1089 i = find(yhook.fds.begin(), yhook.fds.end(), tag);
1090 if(i != yhook.fds.end())
1091 yhook.fds.erase(i);
1094 int yahoohook::connect_async(int id, const char *host, int port, yahoo_connect_callback callback, void *data, int use_ssl) {
1095 struct sockaddr_in serv_addr;
1096 static struct hostent *server;
1097 int servfd;
1098 struct connect_callback_data * ccd;
1099 int error;
1101 if(!(server = gethostbyname(host))) {
1102 errno = h_errno;
1103 return -1;
1106 if((servfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1107 return -1;
1110 memset(&serv_addr, 0, sizeof(serv_addr));
1111 serv_addr.sin_family = AF_INET;
1112 memcpy(&serv_addr.sin_addr.s_addr, *server->h_addr_list, server->h_length);
1113 serv_addr.sin_port = htons(port);
1116 int state = 0;
1117 struct y_c *con = new struct y_c(servfd, use_ssl, state);
1118 error = cw_nb_connect(servfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr), use_ssl, &state);
1119 con->state = state;
1121 if(!error && !state) {
1122 int f = fcntl(servfd, F_GETFL);
1123 fcntl(servfd, F_SETFL, f | O_NONBLOCK);
1124 callback(con, 0, data);
1125 return 0;
1126 } else if((error == -1 && errno == EINPROGRESS) || (state & CW_CONNECT_STARTED)){
1127 ccd = new connect_callback_data;
1128 ccd->callback = callback;
1129 ccd->callback_data = data;
1130 ccd->id = id;
1132 ccd->tag = add_handler(id, con, YAHOO_INPUT_WRITE, ccd);
1133 delete con;
1134 return ccd->tag;
1135 } else {
1136 y_close(con);
1137 callback(NULL, 0, data);
1139 close(servfd);
1140 return -1;
1144 void yahoohook::connect_complete(void *data, struct y_c *con) {
1145 connect_callback_data *ccd = (connect_callback_data *) data;
1146 int so_error;
1147 socklen_t err_size = sizeof(so_error);
1149 remove_handler(0, ccd->tag);
1150 if(getsockopt(con->fd, SOL_SOCKET, SO_ERROR, (char *) &so_error, &err_size) == -1 || so_error != 0) {
1151 if(yhook.logged())
1152 face.log(_("+ [yahoo] direct connection failed"));
1154 cw_close(con->fd);
1155 } else {
1156 ccd->callback(con, so_error, ccd->callback_data);
1159 delete ccd;
1162 int yahoohook::y_write(void *fd, char *buf, int len)
1164 if (!fd)
1165 return -1;
1166 struct y_c *con = (struct y_c *)fd;
1167 return cw_write(con->fd, buf, len, con->ssl);
1170 int yahoohook::y_read(void *fd, char *buf, int len)
1172 if (!fd)
1173 return -1;
1174 struct y_c *con = (struct y_c *)fd;
1175 return cw_read(con->fd, buf, len, con->ssl);
1179 void yahoohook::y_close(void *fd)
1181 struct y_c *con = (struct y_c *)fd;
1182 cw_close(con->fd);
1183 delete con;
1186 void yahoohook::got_ignore(int id, YList * igns) {
1189 void yahoohook::got_cookies(int id) {
1192 void yahoohook::chat_cat_xml(int id, const char *xml) {
1193 face.log(_("+ [yahoo] chat_cat_xml"));
1196 void yahoohook::chat_join(int id, const char *me, const char *room, const char *topic, YList *members, void *fd) {
1197 face.log(_("+ [yahoo] chat_join"));
1200 void yahoohook::chat_userjoin(int id, const char *me, const char *room, struct yahoo_chat_member *who) {
1201 face.log(_("+ [yahoo] chat_userjoin"));
1204 void yahoohook::chat_userleave(int id, const char *me, const char *room, const char *who) {
1205 face.log(_("+ [yahoo] chat_userleave"));
1208 void yahoohook::chat_message(int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8) {
1209 face.log(_("+ [yahoo] chat_message from %s"), who);
1212 void yahoohook::rejected(int id, const char *who, const char *msg) {
1213 face.log(_("+ [yahoo] rejected by %s: %s"), who, msg);
1216 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) {
1219 void yahoohook::webcam_invite(int id, const char *me, const char *from) {
1222 void yahoohook::webcam_invite_reply(int id, const char *me, const char *from, int accept) {
1225 void yahoohook::webcam_closed(int id, const char *who, int reason) {
1228 void yahoohook::webcam_viewer(int id, const char *who, int connect) {
1231 void yahoohook::webcam_data_request(int id, int send) {
1234 void yahoohook::got_buddyicon_request(int id, const char *me, const char *who) {
1237 void yahoohook::got_buddyicon(int id, const char *me, const char *who, const char *url, int checksum) {
1240 void yahoohook::buddyicon_uploaded(int id, const char *url) {
1243 void yahoohook::chat_yahooerror(int id, const char *me) {
1244 face.log(_("+ [yahoo] chat_yahooerror"));
1247 void yahoohook::chat_yahoologout(int id, const char *me) {
1248 face.log(_("+ [yahoo] chat_yahoologout"));
1251 int yahoohook::yahoo_connect(const char *host, int port) {
1252 face.log(_("+ [yahoo] yahoo connect"));
1253 return -1;
1256 void yahoohook::file_transfer_done(int id, int result, void *data) {
1259 char *yahoohook::get_ip_addr(const char *domain) {
1260 face.log(_("+ [yahoo] get_ip_addr %s"), domain);
1261 return NULL;
1264 void yahoohook::got_buddy_change_group(int id, const char *me, const char *who, const char *old_group, const char *new_group) {
1265 face.log(_("+ [yahoo] yahoo buddy_change_group %s from %s to %s"), who, old_group, new_group);
1268 void yahoohook::got_buddyicon_checksum(int id, char const *me, const char *who, int checksum) {
1271 void yahoohook::got_buzz(int id, const char *me, const char *who, long tm) {
1272 face.log(_("+ [yahoo] got buzz from %s"), who);
1275 void yahoohook::got_ft_data(int id, const unsigned char *in, int len, void *data) {
1278 void yahoohook::auth_request(int id, char *who, char *msg) {
1279 imcontact ic(who, yahoo);
1280 string text = cuthtml(msg?msg: "", chCutBR | chLeaveLinks);
1282 yhook.checkinlist(ic);
1283 text = yhook.decode(text, true);
1285 em.store(imauthorization(ic, imevent::incoming, imauthorization::Request, text));
1288 void yahoohook::auth_response(int id, const char *who, char granted, const char *msg) {
1289 imcontact ic(who, yahoo);
1290 string text = cuthtml(msg?msg:"", chCutBR | chLeaveLinks);
1292 //yhook.checkinlist(ic);
1293 text = yhook.decode(text, true);
1294 string message;
1295 if (granted)
1296 message = "The user has accepted your authorization request";
1297 else
1299 message = "The user has rejected your authorization request";
1300 if (!text.empty())
1302 message += " (";
1303 message += text;
1304 message += ")";
1308 em.store(imnotification(ic, message));
1311 int yahoohook::ylog(const char *fmt, ...) {
1312 if(conf->getdebug()) {
1313 char buf[NOTIFBUF];
1314 va_list ap;
1316 va_start(ap, fmt);
1317 vsnprintf(buf, NOTIFBUF, fmt, ap);
1318 va_end(ap);
1320 face.log(buf);
1323 return 0;
1326 void yahoohook::get_fd(int id, void *fd, int error, void *data) {
1327 const char *fname = (const char *) data;
1328 struct y_c *con = (struct y_c *)fd;
1329 char buf[1024];
1330 int size = 0;
1332 if(!error) {
1333 ifstream f(fname);
1335 if(f.is_open()) {
1336 while(!f.eof()) {
1337 f.read(buf, 1024);
1338 cw_write(con->fd, buf, f.tellg(), con->ssl);
1339 size += f.tellg();
1341 f.close();
1345 map<const char *, imfile>::iterator ir = yhook.srfiles.find(fname);
1346 if(ir != yhook.srfiles.end()) {
1347 face.transferupdate(fname, ir->second,
1348 error ? icqface::tsError : icqface::tsFinish,
1349 size, size);
1351 yhook.srfiles.erase(ir);
1354 vector<char *>::iterator i = find(yhook.sfiles.begin(), yhook.sfiles.end(), fname);
1355 if(i != yhook.sfiles.end()) {
1356 delete *i;
1357 yhook.sfiles.erase(i);
1361 void yahoohook::get_url(int id, int fd, int error, const char *filename, unsigned long size, void *data) {
1362 int rsize = 0;
1363 const char *localname = (const char *) data;
1365 if(!error) {
1366 vector<char *>::iterator i = find(yhook.sfiles.begin(), yhook.sfiles.end(), localname);
1367 if(i != yhook.sfiles.end()) {
1368 ofstream f(localname);
1370 if(f.is_open()) {
1371 int r;
1372 char buf[1024];
1373 FILE *fp = fdopen(fd, "r");
1375 while(!feof(fp)) {
1376 r = fread(buf, 1, 1024, fp);
1377 if(r > 0) f.write(buf, r);
1378 rsize += r;
1381 fclose(fp);
1382 f.close();
1383 } else {
1384 error = -1;
1387 delete *i;
1388 yhook.sfiles.erase(i);
1392 map<const char *, imfile>::iterator ir = yhook.srfiles.find(localname);
1393 if(ir != yhook.srfiles.end()) {
1394 face.transferupdate(justfname(localname), ir->second,
1395 error ? icqface::tsError : icqface::tsFinish,
1396 size, rsize);
1398 yhook.srfiles.erase(ir);
1403 #endif