connwrap - initialize gnutls session in cw_connect
[centerim.git] / src / hooks / yahoohook.cc
blob09274de1a110cc8690cc9c6e41cd4616f841e8c4
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;
139 yahoo_register_callbacks(&c);
142 void yahoohook::connect() {
143 icqconf::imaccount acc = conf->getourid(proto);
144 int r;
146 log(logConnecting);
148 if(cid < 0) {
149 yahoo_logoff(cid);
150 yahoo_close(cid);
153 cid = yahoo_init_with_attributes(acc.nickname.c_str(), acc.password.c_str(),
154 "pager_host", acc.server.c_str(),
155 "pager_port", acc.port,
156 (char *) NULL);
158 yahoo_login(cid, stat2int[manualstatus]);
160 if(cid < 0) {
161 string msg = _("+ [yahoo] cannot connect: ");
163 switch(cid) {
164 case -1: msg += _("could not resolve hostname"); break;
165 case -2: msg += _("could not create socket"); break;
166 default: msg += _("verify the pager host and port entered"); break;
169 face.log(msg);
170 } else {
171 fonline = true;
172 flogged = false;
176 void yahoohook::main() {
177 vector<yfd>::iterator i;
178 struct timeval tv;
179 int hsock;
180 fd_set rs, ws, es;
182 FD_ZERO(&rs);
183 FD_ZERO(&ws);
184 FD_ZERO(&es);
186 tv.tv_sec = tv.tv_usec = 0;
187 hsock = 0;
189 for(i = fds.begin(); i != fds.end(); ++i) {
190 struct y_c ic = i->con;
191 if (i->cond & YAHOO_INPUT_READ)
192 FD_SET(ic.fd, &rs);
193 if (i->cond & YAHOO_INPUT_WRITE)
194 FD_SET(ic.fd, &ws);
195 hsock = max(hsock, ic.fd);
198 if(select(hsock+1, &rs, &ws, 0, &tv) > 0) {
199 for(i = fds.begin(); i != fds.end(); ++i) {
200 if(i->isconnect) {
201 if (!cw_nb_connect(i->con.fd, NULL, 0, i->con.ssl, &i->con.state))
203 if (i->con.state & CW_CONNECT_WANT_SOMETHING)
204 continue;
206 else
208 cw_close(i->con.fd);
209 break;
211 struct y_c tc = i->con;
212 connect_complete(i->data, &tc);
213 break;
216 if(FD_ISSET(i->con.fd, &rs)) {
217 yahoo_read_ready(cid, &i->con, i->data);
218 break;
220 if(FD_ISSET(i->con.fd, &ws)) {
221 yahoo_write_ready(cid, &i->con, i->data);
222 break;
228 void yahoohook::getsockets(fd_set &rs, fd_set &ws, fd_set &es, int &hsocket) const {
229 if(online()) {
230 vector<yfd>::const_iterator i;
232 for(i = fds.begin(); i != fds.end(); ++i) {
233 if (i->cond & YAHOO_INPUT_READ)
234 FD_SET(i->con.fd, &rs);
235 if (i->cond & YAHOO_INPUT_WRITE)
236 FD_SET(i->con.fd, &ws);
237 hsocket = max(hsocket, i->con.fd);
242 bool yahoohook::isoursocket(fd_set &rs, fd_set &ws, fd_set &es) const {
243 vector<yfd>::const_iterator i;
245 for(i = fds.begin(); i != fds.end(); ++i)
247 if(i->cond & YAHOO_INPUT_READ && FD_ISSET(i->con.fd, &rs))
248 return true;
250 if(i->cond & YAHOO_INPUT_WRITE && FD_ISSET(i->con.fd, &ws))
251 return true;
253 return false;
256 void yahoohook::disconnect() {
257 if(online()) {
258 yahoo_logoff(cid);
259 time(&timer_close);
263 void yahoohook::disconnected() {
264 if(logged()) {
265 vector<yfd>::const_iterator i;
266 for(i = fds.begin(); i != fds.end(); ++i)
268 cw_close(i->con.fd);
271 fds.clear();
273 logger.putourstatus(proto, getstatus(), ourstatus = offline);
274 clist.setoffline(proto);
275 fonline = false;
276 log(logDisconnected);
277 face.update();
281 void yahoohook::exectimers() {
282 vector<pair<Action, string> >::iterator it;
284 for(it = tobedone.begin(); it != tobedone.end(); ++it) {
285 switch(it->first) {
286 case tbdConfLogon:
287 /* TODO: investigate if copy is really needed here */
288 char *room = strdup(it->second.c_str());
289 yahoo_conference_logon(cid, 0, getmembers(it->second), room);
290 free (room);
291 break;
295 tobedone.clear();
297 if(logged()) {
298 if(timer_current-timer_refresh > PERIOD_REFRESH) {
299 yahoo_refresh(cid);
300 yahoo_keepalive(cid);
301 timer_refresh = timer_current;
303 } else if(timer_close && timer_current-timer_close > PERIOD_CLOSE) {
304 yahoo_close(cid);
305 disconnected();
311 struct tm *yahoohook::timestamp() {
312 return localtime(&timer_current);
315 bool yahoohook::send(const imevent &ev) {
316 icqcontact *c = clist.get(ev.getcontact());
317 string text;
319 if(c) {
320 if(ev.gettype() == imevent::message) {
321 const immessage *m = static_cast<const immessage *>(&ev);
322 if(m) text = rushtmlconv("ku", m->gettext());
324 } else if(ev.gettype() == imevent::url) {
325 const imurl *m = static_cast<const imurl *>(&ev);
326 if(m) text = rushtmlconv("ku", m->geturl()) + "\n\n" + rusconv("kw", m->getdescription());
328 } else if(ev.gettype() == imevent::file) {
329 const imfile *m = static_cast<const imfile *>(&ev);
330 vector<imfile::record> files = m->getfiles();
331 vector<imfile::record>::const_iterator ir;
333 for(ir = files.begin(); ir != files.end(); ++ir) {
334 sfiles.push_back(strdup(ir->fname.c_str()));
335 srfiles[sfiles.back()] = *m;
337 yahoo_send_file(cid, ev.getcontact().nickname.c_str(),
338 m->getmessage().c_str(), justfname(ir->fname).c_str(),
339 ir->size, &get_fd, sfiles.back());
342 return true;
343 } else if (ev.gettype() == imevent::authorization) {
344 const imauthorization *m = static_cast<const imauthorization *> (&ev);
346 switch(m->getauthtype()) {
347 case imauthorization::Granted:
348 yahoo_confirm_buddy(cid, ev.getcontact().nickname.c_str(), 0, 0);
349 break;
351 case imauthorization::Rejected:
352 yahoo_confirm_buddy(cid, ev.getcontact().nickname.c_str(), 1, 0);
353 break;
356 return true;
359 if(!ischannel(c)) {
360 yahoo_send_im(cid, 0, ev.getcontact().nickname.c_str(), text.c_str(), 0, 0);
361 } else {
362 yahoo_conference_message(cid, 0, getmembers(ev.getcontact().nickname.substr(1)),
363 ev.getcontact().nickname.c_str()+1, text.c_str(), 0);
366 return true;
369 return false;
372 bool yahoohook::online() const {
373 return fonline;
376 bool yahoohook::logged() const {
377 return fonline && flogged;
380 bool yahoohook::isconnecting() const {
381 return fonline && !flogged;
384 void yahoohook::sendnewuser(const imcontact &ic) {
385 sendnewuser(ic, true);
388 void yahoohook::sendnewuser(const imcontact &ic, bool report) {
389 if(online() && !ischannel(ic)) {
390 if(logged()) {
391 bool found = false;
392 const YList *buddies = yahoo_get_buddylist(cid);
393 const YList *bud = 0;
395 for(bud = buddies; bud && !found; bud = y_list_next(bud))
396 found = ic.nickname == static_cast<yahoo_buddy *>(bud->data)->id;
398 if(!found) {
399 if(report) log(logContactAdd, ic.nickname.c_str());
400 if (groups.size()>0)
402 vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), clist.get(ic)->getgroupid());
403 if (ig == groups.end())
404 ig = groups.begin();
405 yahoo_add_buddy(cid, ic.nickname.c_str(), ig->getname().c_str(), "");
411 requestinfo(ic);
414 void yahoohook::removeuser(const imcontact &ic) {
415 removeuser(ic, true);
418 void yahoohook::removeuser(const imcontact &ic, bool report) {
419 if(logged()) {
420 if(!ischannel(ic)) {
421 if(report) log(logContactRemove, ic.nickname.c_str());
423 const YList *buddies = yahoo_get_buddylist(cid);
424 const YList *bud = 0;
426 for(bud = buddies; bud; bud = y_list_next(bud)) {
427 if(ic.nickname == ((yahoo_buddy *) bud->data)->id)
428 yahoo_remove_buddy(cid,
429 ((yahoo_buddy *) bud->data)->id,
430 ((yahoo_buddy *) bud->data)->group);
432 } else {
433 if(report)
434 face.log(_("+ [yahoo] leaving the %s conference"),
435 ic.nickname.c_str());
437 yahoo_conference_logoff(cid, 0, getmembers(ic.nickname.substr(1)), ic.nickname.c_str()+1);
442 imstatus yahoohook::yahoo2imstatus(int status) {
443 imstatus st = offline;
445 switch(status) {
446 case YAHOO_STATUS_AVAILABLE:
447 st = available;
448 break;
449 case YAHOO_STATUS_BUSY:
450 st = dontdisturb;
451 break;
452 case YAHOO_STATUS_CUSTOM:
453 case YAHOO_STATUS_BRB:
454 case YAHOO_STATUS_IDLE:
455 case YAHOO_STATUS_ONPHONE:
456 st = away;
457 break;
458 case YAHOO_STATUS_NOTATDESK:
459 st = occupied;
460 break;
461 case YAHOO_STATUS_NOTATHOME:
462 case YAHOO_STATUS_NOTINOFFICE:
463 case YAHOO_STATUS_ONVACATION:
464 case YAHOO_STATUS_STEPPEDOUT:
465 st = notavail;
466 break;
467 case YAHOO_STATUS_OUTTOLUNCH:
468 st = outforlunch;
469 break;
470 case YAHOO_STATUS_INVISIBLE:
471 st = invisible;
472 break;
473 case -1:
474 st = offline;
475 break;
478 return st;
481 bool yahoohook::enabled() const {
482 return true;
485 void yahoohook::setautostatus(imstatus st) {
486 if(st == offline) {
487 if(getstatus() != offline) {
488 disconnect();
490 } else {
491 if(getstatus() == offline) {
492 connect();
494 } else {
495 logger.putourstatus(proto, getstatus(), ourstatus = st);
497 if(st == freeforchat) {
498 /* TODO copy should not be needed here ?*/
499 char *msg = strdup("free for chat");
500 yahoo_set_away(cid, (yahoo_status) stat2int[st], msg, 0);
501 free (msg);
503 } else if(st != away) {
504 yahoo_set_away(cid, (yahoo_status) stat2int[st], 0, 0);
506 } else {
507 char *msg = strdup(rusconv("ku", conf->getawaymsg(proto)).c_str());
508 yahoo_set_away(cid, (yahoo_status) stat2int[st], msg, 1);
509 free (msg);
516 imstatus yahoohook::getstatus() const {
517 return online() ? ourstatus : offline;
520 void yahoohook::requestinfo(const imcontact &ic) {
521 requestfromfound(ic);
523 icqcontact *c = clist.get(ic);
524 if(!c) c = clist.get(contactroot);
526 icqcontact::moreinfo m = c->getmoreinfo();
527 icqcontact::basicinfo b = c->getbasicinfo();
529 m.homepage = "http://profiles.yahoo.com/" + ic.nickname;
530 b.email = ic.nickname + "@yahoo.com";
532 c->setmoreinfo(m);
533 c->setbasicinfo(b);
536 void yahoohook::userstatus(const string &nick, int st, const string &message, bool away) {
537 imcontact ic(nick, proto);
538 icqcontact *c = clist.get(ic);
540 awaymessages[nick] = rusconv("wk", message);
542 if(!c) {
543 c = clist.addnew(ic, false);
546 if(c) {
547 logger.putonline(ic, c->getstatus(), yahoo2imstatus(st));
548 c->setstatus(yahoo2imstatus(st));
552 YList *yahoohook::getmembers(const string &room) {
553 int i;
554 static YList *smemb = 0;
555 vector<string>::iterator ic;
556 map<string, vector<string> >::iterator im;
558 if(smemb) {
559 for(YList *n = smemb; n; n = y_list_next(n))
560 free(n->data);
562 y_list_free(smemb);
563 smemb = 0;
566 if((im = confmembers.find(room)) != confmembers.end())
567 for(ic = im->second.begin(); ic != im->second.end(); ++ic)
568 smemb = y_list_append(smemb, strdup(ic->c_str()));
570 return smemb;
573 string yahoohook::decode(string text, bool utf) {
574 int npos, mpos;
576 text = rushtmlconv(utf ? "uk" : "wk", text);
578 while((npos = text.find("\e[")) != -1) {
579 if((mpos = text.substr(npos).find("m")) == -1)
580 mpos = text.size()-npos-1;
582 text.erase(npos, mpos+1);
585 return text;
588 bool yahoohook::knowntransfer(const imfile &fr) const {
589 return fvalid.find(fr) != fvalid.end();
592 void yahoohook::replytransfer(const imfile &fr, bool accept, const string &localpath) {
593 /* if(accept) {
594 string localname = localpath + "/";
595 localname += fr.getfiles()[0].fname;
596 sfiles.push_back(strdup(localname.c_str()));
597 srfiles[sfiles.back()] = fr;
598 yahoo_get_url_handle(cid, fvalid[fr].c_str(), &get_url, sfiles.back());
600 } else {
601 fvalid.erase(fr);
606 void yahoohook::aborttransfer(const imfile &fr) {
607 face.transferupdate(fr.getfiles().begin()->fname, fr, icqface::tsCancel, 0, 0);
608 fvalid.erase(fr);
611 void yahoohook::lookup(const imsearchparams &params, verticalmenu &dest) {
612 string room;
613 icqcontact *c;
614 vector<string>::const_iterator i;
616 while(!foundguys.empty()) {
617 delete foundguys.back();
618 foundguys.pop_back();
621 yahoo_search_gender gender = YAHOO_GENDER_NONE;
623 switch(params.gender) {
624 case genderMale: gender = YAHOO_GENDER_MALE; break;
625 case genderFemale: gender = YAHOO_GENDER_FEMALE; break;
628 searchonlineonly = params.onlineonly;
629 searchdest = &dest;
631 if(!params.kwords.empty()) {
632 yahoo_search(cid, YAHOO_SEARCH_KEYWORD, decode(params.kwords, false).c_str(),
633 gender, YAHOO_AGERANGE_NONE, params.photo ? 1 : 0, 1);
635 } else if(!params.firstname.empty()) {
636 yahoo_search(cid, YAHOO_SEARCH_NAME, decode(params.firstname, false).c_str(),
637 gender, YAHOO_AGERANGE_NONE, params.photo ? 1 : 0, 1);
639 } else if(!params.room.empty()) {
640 room = params.room.substr(1);
641 i = confmembers[room].begin();
643 while(i != confmembers[room].end()) {
644 if(c = clist.get(imcontact(*i, proto)))
645 searchdest->additem(conf->getcolor(cp_clist_yahoo),
646 c, (string) " " + *i);
648 ++i;
651 face.findready();
652 log(logConfMembers, searchdest->getcount());
654 searchdest->redraw();
655 searchdest = 0;
660 void yahoohook::conferencecreate(const imcontact &confid, const vector<imcontact> &lst) {
661 int i;
662 string room = confid.nickname.substr(1);
664 YList *who = 0;
666 vector<imcontact>::const_iterator il = lst.begin();
667 while(il != lst.end()) {
668 who = y_list_append(who, strdup(il->nickname.c_str()));
669 ++il;
672 yahoo_conference_invite(cid, 0, who, room.c_str(), _("Please join my conference."));
674 for(YList *w = who; w; w = y_list_next(w))
675 free(w->data);
677 y_list_free(who);
680 void yahoohook::requestawaymsg(const imcontact &ic) {
681 icqcontact *c = clist.get(ic);
683 if(c) {
684 if(awaymessages.find(ic.nickname) != awaymessages.end()) {
685 em.store(imnotification(ic, string() + _("Custom status message:") + "\n\n" +
686 awaymessages[ic.nickname]));
688 } else {
689 face.log(_("+ [yahoo] cannot fetch away msg from %s, %s (maybe no away msg set)"),
690 c->getdispnick().c_str(), ic.totext().c_str());
696 void yahoohook::checkinlist(imcontact ic) {
697 bool found = false;
698 icqcontact *c = clist.get(ic);
700 if(c)
701 if(c->inlist()) {
702 const YList *buddies = yahoo_get_buddylist(cid);
704 for(const YList *bud = buddies; bud && !found; ) {
705 yahoo_buddy *yb = (yahoo_buddy *) bud->data;
706 found = (c->getdesc().nickname == yb->id);
707 bud = y_list_next(bud);
710 if(!found) sendnewuser(ic, false);
714 void yahoohook::updatecontact(icqcontact *c) {
715 if(logged() && conf->getgroupmode() != icqconf::nogroups) {
716 bool found = false;
717 const YList *buddies = yahoo_get_buddylist(cid);
718 string newgroupname = groups.getname(c->getgroupid());
720 for(const YList *bud = buddies; bud; ) {
721 yahoo_buddy *yb = (yahoo_buddy *) bud->data;
723 if(c->getdesc().nickname == yb->id) {
724 if(!found) {
725 if(newgroupname != yb->group)
726 yahoo_change_buddy_group(cid, yb->id, yb->group, newgroupname.c_str());
728 found = true;
729 } else {
730 yahoo_remove_buddy(cid, yb->id, yb->group);
734 bud = y_list_next(bud);
739 void yahoohook::renamegroup(const string &oldname, const string &newname) {
740 if(logged()) {
741 string tempname = oldname + "___" + i2str(getpid()) + "_temp";
742 yahoo_group_rename(cid, oldname.c_str(), tempname.c_str());
743 yahoo_group_rename(cid, tempname.c_str(), newname.c_str());
747 // ----------------------------------------------------------------------------
749 void yahoohook::login_response(int id, int succ, const char *url) {
750 vector<string>::iterator in;
752 switch(succ) {
753 case YAHOO_LOGIN_OK:
754 yhook.flogged = true;
755 logger.putourstatus(yahoo, offline, yhook.ourstatus = yhook.manualstatus);
756 yhook.log(logLogged);
757 time(&yhook.timer_refresh);
758 yhook.setautostatus(yhook.manualstatus);
759 yhook.timer_close = 0;
760 break;
762 case YAHOO_LOGIN_LOGOFF:
763 yhook.fonline = yhook.fonline = false;
764 yahoo_close(yhook.cid);
765 face.log(_("+ [yahoo] cannot login"));
766 break;
768 case YAHOO_LOGIN_PASSWD:
769 yhook.fonline = yhook.fonline = false;
770 yahoo_close(yhook.cid);
771 face.log(_("+ [yahoo] cannot login: username and password mismatch"));
772 break;
774 case YAHOO_LOGIN_UNAME:
775 yhook.fonline = yhook.fonline = false;
776 yahoo_close(yhook.cid);
777 face.log(_("+ [yahoo] cannot login: username doesn't exist"));
778 break;
780 case YAHOO_LOGIN_LOCK:
781 yhook.fonline = yhook.fonline = false;
782 yahoo_close(yhook.cid);
783 face.log(_("+ [yahoo] cannot login: the account has been blocked"));
784 face.log(_("+ to reactivate visit %s"), url);
785 break;
787 case YAHOO_LOGIN_DUPL:
788 face.log(_("+ [yahoo] another logon detected"));
789 yahoo_logoff(yhook.cid);
790 yhook.manualstatus = offline;
791 break;
793 case YAHOO_LOGIN_UNKNOWN:
794 case YAHOO_LOGIN_SOCK:
795 face.log(_("+ [yahoo] server closed socket"));
796 yhook.disconnected();
797 break;
800 face.update();
803 void yahoohook::got_buddies(int id, YList *buds) {
804 const YList *buddy;
806 for(buddy = buds; buddy; buddy = y_list_next(buddy)) {
807 yahoo_buddy *bud = static_cast<yahoo_buddy *>(buddy->data);
809 clist.updateEntry(imcontact(bud->id, yahoo), bud->group ? bud->group : "");
813 void yahoohook::got_identities(int id, YList *buds) {
816 void yahoohook::status_changed(int id, const char *who, int stat, const char *msg, int away, int idle, int mobile) {
817 yhook.userstatus(who, stat, msg ? msg : "", (bool) away);
820 void yahoohook::got_im(int id, const char *me, const char *who, const char *msg, long tm, int stat, int utf8) {
821 imcontact ic(who, yahoo);
822 string text = cuthtml(msg, chCutBR | chLeaveLinks);
824 yhook.checkinlist(ic);
825 text = yhook.decode(text, utf8);
827 if(!text.empty()) {
828 em.store(immessage(ic, imevent::incoming, text, tm));
832 void yahoohook::got_search_result(int id, int found, int start, int total, YList *contacts) {
833 yahoo_found_contact *fc;
834 icqcontact *c;
835 YList *ir;
836 string sg, line;
838 if(!yhook.searchdest)
839 return;
841 for(ir = contacts; ir; ir = ir->next) {
842 fc = (yahoo_found_contact *) ir->data;
844 if(yhook.searchonlineonly && !fc->online)
845 continue;
847 c = new icqcontact(imcontact(fc->id, yahoo));
849 icqcontact::basicinfo binfo = c->getbasicinfo();
850 icqcontact::moreinfo minfo = c->getmoreinfo();
852 if(!fc->id || !fc->gender)
853 continue;
855 c->setnick(fc->id);
856 c->setdispnick(c->getnick());
858 sg = up(fc->gender);
859 if(sg == "MALE") minfo.gender = genderMale;
860 else if(sg == "FEMALE") minfo.gender = genderFemale;
862 minfo.age = fc->age;
863 if(fc->location) binfo.street = fc->location;
865 line = (fc->online ? "o " : " ") + c->getnick();
867 if(fc->age || fc->location || strlen(fc->gender) >= 4) {
868 line += " <";
869 if(fc->age) line += i2str(fc->age);
871 if(strlen(fc->gender) >= 4) {
872 if(fc->age) line += ", ";
873 line += fc->gender;
876 if(fc->location && strlen(fc->location)) {
877 if(fc->age || strlen(fc->gender) >= 4) line += ", ";
878 line += fc->location;
881 line += ">";
884 c->setbasicinfo(binfo);
885 c->setmoreinfo(minfo);
887 yhook.foundguys.push_back(c);
888 yhook.searchdest->additem(conf->getcolor(cp_clist_yahoo), c, line);
891 yhook.searchdest->redraw();
893 if(start + found >= total) {
894 face.findready();
895 yhook.log(logSearchFinished, yhook.foundguys.size());
896 yhook.searchdest = 0;
897 } else {
898 yahoo_search_again(yhook.cid, -1);
902 void yahoohook::got_conf_invite(int id, const char *me, const char *who, const char *room, const char *msg, YList *members) {
903 icqconf::imaccount acc = conf->getourid(yahoo);
904 string confname = (string) "#" + room, inviter, text;
905 vector<string>::iterator ic;
906 char buf[NOTIFBUF];
907 int i;
909 imcontact cont(confname, yahoo);
910 icqcontact *c = clist.get(cont);
911 if(!c) c = clist.addnew(cont);
913 inviter = confname.substr(1);
914 if((i = inviter.rfind("-")) != -1) {
915 inviter.erase(i);
918 snprintf(buf, NOTIFBUF, _("The user %s has invited you to the %s conference, the topic there is: %s"),
919 yhook.rusconv("wk", inviter).c_str(),
920 yhook.rusconv("wk", room).c_str(),
921 yhook.rusconv("wk", msg).c_str());
923 text = (string) buf + "\n\n" + _("Current conference members are: ");
924 yhook.confmembers[room].push_back(inviter);
926 for(YList *m = members; m; m = y_list_next(m)) {
927 string id = (char *) m->data;
929 if(id != acc.nickname)
930 if(find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), id) == yhook.confmembers[room].end()) {
931 yhook.confmembers[room].push_back(id);
935 for(ic = yhook.confmembers[room].begin(); ic != yhook.confmembers[room].end(); ) {
936 text += *ic;
937 if(++ic != yhook.confmembers[room].end())
938 text += ", ";
941 c->setstatus(available);
942 em.store(imnotification(cont, text));
943 em.store(imnotification(cont, _("Auto-joined the conference")));
945 yhook.tobedone.push_back(make_pair(tbdConfLogon, room));
948 void yahoohook::conf_userdecline(int id, const char *me, const char *who, const char *room, const char *msg) {
949 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
950 char buf[NOTIFBUF];
952 if(c) {
953 snprintf(buf, NOTIFBUF, _("The user %s has declined your invitation to join the conference"), who);
954 em.store(imnotification(c, buf));
958 void yahoohook::conf_userjoin(int id, const char *me, const char *who, const char *room) {
959 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
960 char buf[NOTIFBUF];
962 if(c) {
963 snprintf(buf, NOTIFBUF, _("The user %s has joined the conference"), who);
965 if(find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), who) == yhook.confmembers[room].end())
966 yhook.confmembers[room].push_back(who);
968 em.store(imnotification(c, buf));
972 void yahoohook::conf_userleave(int id, const char *me, const char *who, const char *room) {
973 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
974 char buf[NOTIFBUF];
975 vector<string>::iterator im;
977 if(c) {
978 snprintf(buf, NOTIFBUF, _("The user %s has left the conference"), who);
979 em.store(imnotification(c, buf));
981 im = find(yhook.confmembers[room].begin(), yhook.confmembers[room].end(), who);
982 if(im != yhook.confmembers[room].end()) yhook.confmembers[room].erase(im);
986 void yahoohook::conf_message(int id, const char *me, const char *who, const char *room, const char *msg, int utf8) {
987 icqcontact *c = clist.get(imcontact((string) "#" + room, yahoo));
989 string text = (string) who + ": " + cuthtml(msg, chCutBR | chLeaveLinks);
990 text = yhook.decode(text, utf8);
992 if(c) em.store(immessage(c, imevent::incoming, text));
995 void yahoohook::got_file(int id, const char *me, const char *who, const char *msg, const char *fname, unsigned long fesize, char *trid) {
996 if(!who || !fname || !trid)
997 return;
999 int pos;
1000 imfile::record r;
1001 r.fname = fname;
1002 r.size = fesize;
1003 if(!fesize) r.size = -1;
1005 if((pos = r.fname.find('?')) != -1)
1006 r.fname.erase(pos);
1008 imfile fr(imcontact(who, yahoo), imevent::incoming, "",
1009 vector<imfile::record>(1, r));
1011 yhook.fvalid[fr] = trid;
1012 em.store(fr);
1014 face.transferupdate(fname, fr, icqface::tsInit, fesize, 0);
1017 void yahoohook::contact_added(int id, const char *myid, const char *who, const char *msg) {
1018 string text = _("The user has added you to his/her contact list");
1020 if(msg)
1021 if(strlen(msg)) {
1022 text += (string) ", " + _("the message was: ") + msg;
1025 em.store(imnotification(imcontact(who, yahoo), text));
1028 void yahoohook::typing_notify(int id, const char *me, const char *who, int stat) {
1029 icqcontact *c = clist.get(imcontact(who, yahoo));
1030 if(c) c->setlasttyping(stat ? timer_current : 0);
1033 void yahoohook::game_notify(int id, const char *me, const char *who, int stat, const char *msg) {
1036 void yahoohook::mail_notify(int id, const char *from, const char *subj, int cnt) {
1037 char buf[NOTIFBUF];
1039 if(from && subj) {
1040 snprintf(buf, NOTIFBUF, _("+ [yahoo] e-mail from %s, %s"), from, subj);
1041 face.log(buf);
1042 clist.get(contactroot)->playsound(imevent::email);
1046 void yahoohook::system_message(int id, const char *me, const char *who, const char *msg) {
1047 face.log(_("+ [yahoo] system (%s): %s"), who, msg);
1050 void yahoohook::got_ping(int id, const char *msg) {
1051 // face.log(_("+ [yahoo] ping: %s"), msg);
1054 void yahoohook::error(int id, const char *err, int fatal, int num) {
1055 if(fatal) {
1056 face.log(_("+ [yahoo] fatal error: %s"), err);
1057 yhook.disconnected();
1059 else {
1060 face.log(_("[yahoo] error %s"), err);
1064 int yahoohook::add_handler(int id, void *fd, yahoo_input_condition cond, void *data) {
1065 int tag = -1;
1066 struct y_c *con = (struct y_c *)fd;
1068 yhook.fds.push_back(yfd(con->fd, data, con->ssl, cond));
1069 tag = yhook.fds.back().tag;
1071 return tag;
1074 void yahoohook::remove_handler(int id, int tag) {
1075 vector<yfd>::iterator i;
1077 i = find(yhook.fds.begin(), yhook.fds.end(), tag);
1078 if(i != yhook.fds.end())
1079 yhook.fds.erase(i);
1082 int yahoohook::connect_async(int id, const char *host, int port, yahoo_connect_callback callback, void *data, int use_ssl) {
1083 struct sockaddr_in serv_addr;
1084 static struct hostent *server;
1085 int servfd;
1086 struct connect_callback_data * ccd;
1087 int error;
1089 if(!(server = gethostbyname(host))) {
1090 errno = h_errno;
1091 return -1;
1094 if((servfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1095 return -1;
1098 memset(&serv_addr, 0, sizeof(serv_addr));
1099 serv_addr.sin_family = AF_INET;
1100 memcpy(&serv_addr.sin_addr.s_addr, *server->h_addr_list, server->h_length);
1101 serv_addr.sin_port = htons(port);
1104 int state = 0;
1105 struct y_c *con = new struct y_c(servfd, use_ssl, state);
1106 error = cw_nb_connect(servfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr), use_ssl, &state);
1107 con->state = state;
1109 if(!error && !state) {
1110 int f = fcntl(servfd, F_GETFL);
1111 fcntl(servfd, F_SETFL, f | O_NONBLOCK);
1112 callback(con, 0, data);
1113 return 0;
1114 } else if((error == -1 && errno == EINPROGRESS) || (state & CW_CONNECT_STARTED)){
1115 ccd = new connect_callback_data;
1116 ccd->callback = callback;
1117 ccd->callback_data = data;
1118 ccd->id = id;
1120 ccd->tag = add_handler(id, con, YAHOO_INPUT_WRITE, ccd);
1121 delete con;
1122 return ccd->tag;
1123 } else {
1124 y_close(con);
1125 callback(NULL, 0, data);
1127 close(servfd);
1128 return -1;
1132 void yahoohook::connect_complete(void *data, struct y_c *con) {
1133 connect_callback_data *ccd = (connect_callback_data *) data;
1134 int so_error;
1135 socklen_t err_size = sizeof(so_error);
1137 remove_handler(0, ccd->tag);
1138 if(getsockopt(con->fd, SOL_SOCKET, SO_ERROR, (char *) &so_error, &err_size) == -1 || so_error != 0) {
1139 if(yhook.logged())
1140 face.log(_("+ [yahoo] direct connection failed"));
1142 cw_close(con->fd);
1143 } else {
1144 ccd->callback(con, so_error, ccd->callback_data);
1147 delete ccd;
1150 int yahoohook::y_write(void *fd, char *buf, int len)
1152 if (!fd)
1153 return -1;
1154 struct y_c *con = (struct y_c *)fd;
1155 return cw_write(con->fd, buf, len, con->ssl);
1158 int yahoohook::y_read(void *fd, char *buf, int len)
1160 if (!fd)
1161 return -1;
1162 struct y_c *con = (struct y_c *)fd;
1163 return cw_read(con->fd, buf, len, con->ssl);
1167 void yahoohook::y_close(void *fd)
1169 struct y_c *con = (struct y_c *)fd;
1170 cw_close(con->fd);
1171 delete con;
1174 void yahoohook::got_ignore(int id, YList * igns) {
1177 void yahoohook::got_cookies(int id) {
1180 void yahoohook::chat_cat_xml(int id, const char *xml) {
1183 void yahoohook::chat_join(int id, const char *me, const char *room, const char *topic, YList *members, void *fd) {
1186 void yahoohook::chat_userjoin(int id, const char *me, const char *room, struct yahoo_chat_member *who) {
1189 void yahoohook::chat_userleave(int id, const char *me, const char *room, const char *who) {
1192 void yahoohook::chat_message(int id, const char *me, const char *who, const char *room, const char *msg, int msgtype, int utf8) {
1195 void yahoohook::rejected(int id, const char *who, const char *msg) {
1198 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) {
1201 void yahoohook::webcam_invite(int id, const char *me, const char *from) {
1204 void yahoohook::webcam_invite_reply(int id, const char *me, const char *from, int accept) {
1207 void yahoohook::webcam_closed(int id, const char *who, int reason) {
1210 void yahoohook::webcam_viewer(int id, const char *who, int connect) {
1213 void yahoohook::webcam_data_request(int id, int send) {
1216 void yahoohook::auth_request(int id, char *who, char *msg) {
1217 imcontact ic(who, yahoo);
1218 string text = cuthtml(msg?msg: "", chCutBR | chLeaveLinks);
1220 yhook.checkinlist(ic);
1221 text = yhook.decode(text, true);
1223 em.store(imauthorization(ic, imevent::incoming, imauthorization::Request, text));
1226 void yahoohook::auth_response(int id, const char *who, char granted, const char *msg) {
1227 imcontact ic(who, yahoo);
1228 string text = cuthtml(msg?msg:"", chCutBR | chLeaveLinks);
1230 //yhook.checkinlist(ic);
1231 text = yhook.decode(text, true);
1232 string message;
1233 if (granted)
1234 message = "The user has accepted your authorization request";
1235 else
1237 message = "The user has rejected your authorization request";
1238 if (!text.empty())
1240 message += " (";
1241 message += text;
1242 message += ")";
1246 em.store(imnotification(ic, message));
1249 int yahoohook::ylog(const char *fmt, ...) {
1250 if(conf->getdebug()) {
1251 char buf[NOTIFBUF];
1252 va_list ap;
1254 va_start(ap, fmt);
1255 vsnprintf(buf, NOTIFBUF, fmt, ap);
1256 va_end(ap);
1258 face.log(buf);
1261 return 0;
1264 void yahoohook::get_fd(int id, void *fd, int error, void *data) {
1265 const char *fname = (const char *) data;
1266 struct y_c *con = (struct y_c *)fd;
1267 char buf[1024];
1268 int size = 0;
1270 if(!error) {
1271 ifstream f(fname);
1273 if(f.is_open()) {
1274 while(!f.eof()) {
1275 f.read(buf, 1024);
1276 cw_write(con->fd, buf, f.tellg(), con->ssl);
1277 size += f.tellg();
1279 f.close();
1283 map<const char *, imfile>::iterator ir = yhook.srfiles.find(fname);
1284 if(ir != yhook.srfiles.end()) {
1285 face.transferupdate(fname, ir->second,
1286 error ? icqface::tsError : icqface::tsFinish,
1287 size, size);
1289 yhook.srfiles.erase(ir);
1292 vector<char *>::iterator i = find(yhook.sfiles.begin(), yhook.sfiles.end(), fname);
1293 if(i != yhook.sfiles.end()) {
1294 delete *i;
1295 yhook.sfiles.erase(i);
1299 void yahoohook::get_url(int id, int fd, int error, const char *filename, unsigned long size, void *data) {
1300 int rsize = 0;
1301 const char *localname = (const char *) data;
1303 if(!error) {
1304 vector<char *>::iterator i = find(yhook.sfiles.begin(), yhook.sfiles.end(), localname);
1305 if(i != yhook.sfiles.end()) {
1306 ofstream f(localname);
1308 if(f.is_open()) {
1309 int r;
1310 char buf[1024];
1311 FILE *fp = fdopen(fd, "r");
1313 while(!feof(fp)) {
1314 r = fread(buf, 1, 1024, fp);
1315 if(r > 0) f.write(buf, r);
1316 rsize += r;
1319 fclose(fp);
1320 f.close();
1321 } else {
1322 error = -1;
1325 delete *i;
1326 yhook.sfiles.erase(i);
1330 map<const char *, imfile>::iterator ir = yhook.srfiles.find(localname);
1331 if(ir != yhook.srfiles.end()) {
1332 face.transferupdate(justfname(localname), ir->second,
1333 error ? icqface::tsError : icqface::tsFinish,
1334 size, rsize);
1336 yhook.srfiles.erase(ir);
1341 #endif