1 /*
2 *
3 * centerim IRC protocol handling class
4 * $Id: irchook.cc,v 1.80 2004/12/20 00:54:02 konst Exp $
5 *
6 * Copyright (C) 2001-2004 by Konstantin Klyagin <k@thekonst.net>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * USA
22 *
23 */
24 
25 #include "irchook.h"
26 
27 #ifdef BUILD_IRC
28 
29 #include "icqgroups.h"
30 #include "icqface.h"
31 #include "icqcontacts.h"
32 #include "imlogger.h"
33 
34 #include "accountmanager.h"
35 #include "eventmanager.h"
36 
37 #include "centerim.h"
38 
39 #include <iterator>
40 #include <sstream>
41 
42 #define NOTIFBUF 512
43 
44 // ----------------------------------------------------------------------------
45 
46 irchook irhook;
47 
irchook()48 irchook::irchook()
49     : abstracthook(irc), handle(firetalk_create_handle(firetalk_find_protocol("IRC"), 0)),
50       fonline(false), flogged(false), ourstatus(offline)
51 {
52     fcapabs.insert(hookcapab::setaway);
53     fcapabs.insert(hookcapab::fetchaway);
54     fcapabs.insert(hookcapab::changenick);
55     fcapabs.insert(hookcapab::optionalpassword);
56     fcapabs.insert(hookcapab::ping);
57     fcapabs.insert(hookcapab::version);
58     fcapabs.insert(hookcapab::files);
59     fcapabs.insert(hookcapab::cltemporary);
60     fcapabs.insert(hookcapab::directadd);
61     fcapabs.insert(hookcapab::conferencing);
62     fcapabs.insert(hookcapab::channelpasswords);
63 }
64 
~irchook()65 irchook::~irchook() {
66 }
67 
init()68 void irchook::init() {
69     int i;
70 
71     manualstatus = conf->getstatus(irc);
72 
73     for(i = 0; i < clist.count; i++) {
74 	icqcontact *c = (icqcontact *) clist.at(i);
75 
76 	if(c->getdesc().pname == irc)
77 	if(ischannel(c))
78 	if(c->getbasicinfo().requiresauth) {
79 	    channels.push_back(channelInfo(c->getdesc().nickname));
80 	    channels.back().joined = true;
81 	    channels.back().passwd = c->getbasicinfo().zip;
82 	}
83     }
84 
85     firetalk_register_callback(handle, FC_CONNECTED, &connected);
86     firetalk_register_callback(handle, FC_CONNECTFAILED, &connectfailed);
87     firetalk_register_callback(handle, FC_DISCONNECT, &disconnected);
88     firetalk_register_callback(handle, FC_NEWNICK, &newnick);
89     firetalk_register_callback(handle, FC_IM_GOTINFO, &gotinfo);
90     firetalk_register_callback(handle, FC_IM_GOTCHANNELS, &gotchannels);
91     firetalk_register_callback(handle, FC_IM_GETMESSAGE, &getmessage);
92     firetalk_register_callback(handle, FC_IM_GETACTION, &getaction);
93     firetalk_register_callback(handle, FC_IM_BUDDYONLINE, &buddyonline);
94     firetalk_register_callback(handle, FC_IM_BUDDYOFFLINE, &buddyoffline);
95     firetalk_register_callback(handle, FC_IM_BUDDYAWAY, &buddyaway);
96     firetalk_register_callback(handle, FC_IM_BUDDYUNAWAY, &buddyonline);
97     firetalk_register_callback(handle, FC_CHAT_LISTMEMBER, &listmember);
98     firetalk_register_callback(handle, FC_CHAT_LIST_EXTENDED, &listextended);
99     firetalk_register_callback(handle, FC_CHAT_END_EXTENDED, &endextended);
100     firetalk_register_callback(handle, FC_CHAT_NAMES, &chatnames);
101     firetalk_register_callback(handle, FC_CHAT_GETMESSAGE, &chatmessage);
102     firetalk_register_callback(handle, FC_CHAT_GETACTION, &chataction);
103     firetalk_register_callback(handle, FC_CHAT_JOINED, &chatjoined);
104     firetalk_register_callback(handle, FC_CHAT_LEFT, &chatleft);
105     firetalk_register_callback(handle, FC_CHAT_KICKED, &chatkicked);
106     firetalk_register_callback(handle, FC_CHAT_OPPED, &chatopped);
107     firetalk_register_callback(handle, FC_CHAT_DEOPPED, &chatdeopped);
108     firetalk_register_callback(handle, FC_ERROR, &errorhandler);
109     firetalk_register_callback(handle, FC_IM_USER_NICKCHANGED, &nickchanged);
110     firetalk_register_callback(handle, FC_NEEDPASS, &needpass);
111     firetalk_register_callback(handle, FC_FILE_OFFER, &fileoffer);
112     firetalk_register_callback(handle, FC_FILE_START, &filestart);
113     firetalk_register_callback(handle, FC_FILE_PROGRESS, &fileprogress);
114     firetalk_register_callback(handle, FC_FILE_FINISH, &filefinish);
115     firetalk_register_callback(handle, FC_FILE_ERROR, &fileerror);
116     firetalk_register_callback(handle, FC_CHAT_USER_JOINED, &chatuserjoined);
117     firetalk_register_callback(handle, FC_CHAT_USER_LEFT, &chatuserleft);
118     firetalk_register_callback(handle, FC_CHAT_USER_KICKED, &chatuserkicked);
119     firetalk_register_callback(handle, FC_CHAT_GOTTOPIC, &chatgottopic);
120     firetalk_register_callback(handle, FC_CHAT_USER_OPPED, &chatuseropped);
121     firetalk_register_callback(handle, FC_CHAT_USER_DEOPPED, &chatuserdeopped);
122 
123     firetalk_subcode_register_request_callback(handle, "VERSION", &subrequest);
124 
125     firetalk_subcode_register_reply_callback(handle, "PING", &subreply);
126     firetalk_subcode_register_reply_callback(handle, "VERSION", &subreply);
127 
128     if(conf->getdebug())
129 	firetalk_register_callback(handle, FC_LOG, &fclog);
130 }
131 
connect()132 void irchook::connect() {
133     icqconf::imaccount acc = conf->getourid(irc);
134     log(logConnecting);
135 
136     firetalk_register_callback(handle, FC_DISCONNECT, 0);
137     firetalk_disconnect(handle);
138     firetalk_register_callback(handle, FC_DISCONNECT, &disconnected);
139 
140     fonline = firetalk_signon(handle, acc.server.c_str(),
141 	acc.port, acc.nickname.c_str()) == FE_SUCCESS;
142 
143     if(fonline) {
144 	flogged = false;
145     } else {
146 	face.log(_("+ [irc] unable to connect to the server"));
147     }
148 }
149 
disconnect()150 void irchook::disconnect() {
151     if(fonline) {
152 	firetalk_disconnect(handle);
153     }
154 }
155 
exectimers()156 void irchook::exectimers() {
157 }
158 
main()159 void irchook::main() {
160     firetalk_select();
161 }
162 
getsockets(fd_set & rfds,fd_set & wfds,fd_set & efds,int & hsocket) const163 void irchook::getsockets(fd_set &rfds, fd_set &wfds, fd_set &efds, int &hsocket) const {
164     int *r, *w, *e, *sr, *sw, *se;
165 
166     firetalk_getsockets(firetalk_find_protocol("IRC"), &sr, &sw, &se);
167 
168     for(r = sr; *r; r++) {
169 	if(*r > hsocket) hsocket = *r;
170 	FD_SET(*r, &rfds);
171     }
172 
173     for(w = sw; *w; w++) {
174 	if(*w > hsocket) hsocket = *w;
175 	FD_SET(*w, &wfds);
176     }
177 
178     for(e = se; *e; e++) {
179 	if(*e > hsocket) hsocket = *e;
180 	FD_SET(*e, &efds);
181     }
182 
183     delete sr;
184     delete sw;
185     delete se;
186 }
187 
isoursocket(fd_set & rfds,fd_set & wfds,fd_set & efds) const188 bool irchook::isoursocket(fd_set &rfds, fd_set &wfds, fd_set &efds) const {
189     bool res = false;
190     int *r, *w, *e, *sr, *sw, *se;
191 
192     if(online()) {
193 	firetalk_getsockets(firetalk_find_protocol("IRC"), &sr, &sw, &se);
194 
195 	for(r = sr; *r; r++) res = res || FD_ISSET(*r, &rfds);
196 	for(w = sw; *w; w++) res = res || FD_ISSET(*w, &wfds);
197 	for(e = se; *e; e++) res = res || FD_ISSET(*e, &efds);
198 
199 	delete sr;
200 	delete sw;
201 	delete se;
202     }
203 
204     return res;
205 }
206 
online() const207 bool irchook::online() const {
208     return fonline;
209 }
210 
logged() const211 bool irchook::logged() const {
212     return flogged && fonline;
213 }
214 
enabled() const215 bool irchook::enabled() const {
216     return true;
217 }
218 
isconnecting() const219 bool irchook::isconnecting() const {
220     return fonline && !flogged;
221 }
222 
send(const imevent & ev)223 bool irchook::send(const imevent &ev) {
224     icqcontact *c = clist.get(ev.getcontact());
225     string text, cmd;
226     bool result = true;
227 
228     if(c) {
229 	if(ev.gettype() == imevent::message) {
230 	    const immessage *m = static_cast<const immessage *>(&ev);
231 	    text = rusconv("kw", m->gettext());
232 
233 	} else if(ev.gettype() == imevent::url) {
234 	    const imurl *m = static_cast<const imurl *>(&ev);
235 	    text = rushtmlconv("kw", m->geturl()) + "\n\n" + rushtmlconv("kw", m->getdescription());
236 
237 	} else if(ev.gettype() == imevent::file) {
238 	    const imfile *m = static_cast<const imfile *>(&ev);
239 	    vector<imfile::record> files = m->getfiles();
240 	    vector<imfile::record>::const_iterator ir;
241 
242 	    for(ir = files.begin(); ir != files.end(); ++ir) {
243 		imfile::record r;
244 		r.fname = ir->fname;
245 		r.size = ir->size;
246 
247 		imfile fr(c->getdesc(), imevent::outgoing, "",
248 		    vector<imfile::record>(1, r));
249 
250 		firetalk_file_offer(handle, c->getdesc().nickname.c_str(),
251 		    ir->fname.c_str(), &transferinfo[fr].first);
252 	    }
253 
254 	    return true;
255 	}
256 
257 	string original = text;
258 	int pos = -1;
259 
260 	while (original.length()>0)
261 	{
262 	if ((pos = original.find("\n")) != -1)  // split by newlines into separate commands, drop empty ones
263 	{
264 		if (pos>1)
265 		{
266 			text = original.substr(0, pos-1);
267 			original.erase(0, pos+1);
268 		}
269 		else
270 		{
271 			original.erase(0, pos+1);
272 			continue;
273 		}
274 	}
275 	else
276 	{
277 		text = original;
278 		original.erase();
279 	}
280 	if(text.substr(0, 1) == "/") {
281 	    text.erase(0, 1);
282 	    cmd = up(getword(text));
283 
284 	    if(cmd == "ME") {
285 		if(ischannel(c)) return firetalk_chat_send_action(handle,
286 		    c->getdesc().nickname.c_str(), text.c_str(), 0) == FE_SUCCESS;
287 		else return firetalk_im_send_action(handle,
288 		    c->getdesc().nickname.c_str(), text.c_str(), 0) == FE_SUCCESS;
289 
290 	    } else if(cmd == "KICK") {
291 		text = cmd + " " + c->getdesc().nickname + " " + text;
292 
293 	    } else if(cmd == "OP") {
294 		text = (string) "mode " + c->getdesc().nickname + " +o " + text;
295 
296 	    } else if(cmd == "DEOP") {
297 		text = (string) "mode " + c->getdesc().nickname + " -o " + text;
298 
299 	    } else if(cmd == "RAW") {
300 		// leave text intact
301 
302 	    } else {
303 		text.insert(0, cmd + " ");
304 
305 	    }
306 
307 	    rawcommand(text);
308 	}
309 
310 	if(ischannel(c)) {
311 	    if (firetalk_chat_send_message(handle,
312 		c->getdesc().nickname.c_str(), text.c_str(), 0) != FE_SUCCESS)
313 			result = false;
314 
315 	} else {
316 	    if (firetalk_im_send_message(handle,
317 		c->getdesc().nickname.c_str(), text.c_str(), 0) != FE_SUCCESS)
318 			result = false;
319 
320 	}
321     	}
322     	return result;
323 	}
324 
325     return false;
326 }
327 
sendnewuser(const imcontact & ic)328 void irchook::sendnewuser(const imcontact &ic) {
329     icqcontact *c;
330 
331     if(online()) {
332 	if(!ischannel(ic)) {
333 	    vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), clist.get(ic)->getgroupid());
334 	    if(ig != groups.end()) {
335 	    	firetalk_im_add_buddy(handle, ic.nickname.c_str(), ig->getname().c_str(), "");
336 	    }
337 	    requestinfo(ic);
338 	} else {
339 	    vector<channelInfo> ch = getautochannels();
340 	    if(find(ch.begin(), ch.end(), ic.nickname) == ch.end()) {
341 		ch.push_back(ic.nickname);
342 		ch.back().joined = true;
343 		if(c = clist.get(ic)) {
344 		    ch.back().passwd = c->getbasicinfo().zip;
345 		}
346 		setautochannels(ch);
347 	    }
348 	}
349     }
350 }
351 
removeuser(const imcontact & ic)352 void irchook::removeuser(const imcontact &ic) {
353     if(online()) {
354 	if(!ischannel(ic)) {
355 	    firetalk_im_remove_buddy(handle, ic.nickname.c_str());
356 	} else {
357 	    vector<channelInfo> ch = getautochannels();
358 	    vector<channelInfo>::iterator ich = find(ch.begin(), ch.end(), ic.nickname);
359 	    if(ich != ch.end()) {
360 		ch.erase(ich);
361 		setautochannels(ch);
362 	    }
363 	}
364     }
365 }
366 
setautostatus(imstatus st)367 void irchook::setautostatus(imstatus st) {
368     if(st != offline) {
369 	if(getstatus() == offline) {
370 	    connect();
371 	} else {
372 	    if(getstatus() != st) {
373 		logger.putourstatus(irc, getstatus(), ourstatus = st);
374 
375 		switch(st) {
376 		    case away:
377 		    case notavail:
378 		    case outforlunch:
379 		    case occupied:
380 			firetalk_set_away(handle, conf->getawaymsg(irc).c_str(), 0);
381 			break;
382 
383 		    default:
384 			firetalk_set_away(handle, 0, 0);
385 			break;
386 		}
387 	    }
388 	}
389     } else {
390 	if(getstatus() != offline) {
391 	    disconnect();
392 	}
393     }
394 
395     face.update();
396 }
397 
getstatus() const398 imstatus irchook::getstatus() const {
399     return (flogged && fonline) ? ourstatus : offline;
400 }
401 
requestinfo(const imcontact & c)402 void irchook::requestinfo(const imcontact &c) {
403     firetalk_im_get_info(handle, c.nickname.c_str());
404 }
405 
sendupdateuserinfo(icqcontact & c,const string & newpass)406 void irchook::sendupdateuserinfo(icqcontact &c, const string &newpass) {
407     const icqcontact::basicinfo &b = c.getbasicinfo();
408 
409     ircname = b.fname;
410     if(!b.lname.empty()) {
411 	if(!ircname.empty()) ircname += " ";
412 	ircname += b.lname;
413     }
414 }
415 
lookup(const imsearchparams & params,verticalmenu & dest)416 void irchook::lookup(const imsearchparams &params, verticalmenu &dest) {
417     string rooms = params.room, room;
418     bool ready = true;
419     vector<channelInfo>::iterator ic;
420 
421     searchdest = &dest;
422 
423     emailsub = params.email;
424     namesub = params.firstname;
425     searchsincelast = params.sincelast && !params.room.empty();
426 
427     searchchannels.clear();
428     extlisted.clear();
429 
430     while(!foundguys.empty()) {
431 	delete foundguys.back();
432 	foundguys.pop_back();
433     }
434 
435     if(!params.room.empty()) {
436 	smode = Channel;
437 
438 	while(!(room = getword(rooms)).empty()) {
439 	    if(room[0] != '#') room.insert(0, "#");
440 	    searchchannels.push_back(room);
441             ic = find(irhook.channels.begin(), irhook.channels.end(), room);
442 
443 	    if(ic == irhook.channels.end()) {
444 		irhook.channels.push_back(channelInfo(room));
445 		ic = irhook.channels.end()-1;
446 	    }
447 
448 	    if(!ic->joined) {
449 		firetalk_chat_join(handle, room.c_str());
450 		ready = false;
451 	    }
452 
453 	    if(emailsub.empty() && namesub.empty()) {
454 	/*	if(ic->fetched) {*/
455 		    ic->nicks.clear();
456 		    firetalk_chat_listmembers(handle, room.c_str());
457 /*		} else {
458 		    ready = false;
459 		}*/
460 
461 	    } else {
462 		ready = false;
463 		if(ic->joined) {
464 		    ic->nicks.clear();
465 		    firetalk_chat_requestextended(handle, params.room.c_str());
466 		}
467 
468 	    }
469 	}
470 
471 	if(ready)
472 	    processnicks();
473 
474     } else if(!params.email.empty()) {
475 	smode = Email;
476 	searchchannels.push_back("");
477 	firetalk_im_searchemail(handle, ("*" + params.email + "*").c_str());
478 
479     }
480 }
481 
processnicks()482 void irchook::processnicks() {
483     string dnick;
484     char *nick;
485     vector<string> foundnicks;
486     static vector<string> lastfoundnicks;
487     vector<string>::iterator in, isn;
488     vector<channelInfo>::iterator ir;
489     bool remove;
490     icqcontact *c;
491     int npos;
492 
493     if(!searchdest)
494 	return;
495 
496     ir = find(channels.begin(), channels.end(), *searchchannels.begin());
497     if(ir != channels.end())
498 	foundnicks = ir->nicks;
499 
500     sort(foundnicks.begin(), foundnicks.end());
501 
502     if(searchchannels.size() > 1) {
503 	for(in = foundnicks.begin(); in != foundnicks.end(); ) {
504 	    remove = false;
505 
506 	    for(ir = channels.begin(); !remove && (ir != channels.end()); ++ir) {
507 		if(find(searchchannels.begin(), searchchannels.end(), ir->name) == searchchannels.end())
508 		    continue;
509 		if(ir->name == *searchchannels.begin())
510 		    continue;
511 
512 		if(find(ir->nicks.begin(), ir->nicks.end(), *in) == ir->nicks.end()) {
513 		    /*
514 		    *
515 		    * Not found in one of other channels. Remove it from the
516 		    * first channel's list.
517 		    *
518 		    */
519 		    remove = true;
520 		}
521 	    }
522 
523 	    if(remove) {
524 		foundnicks.erase(in);
525 		in = foundnicks.begin();
526 	    } else {
527 		in++;
528 	    }
529 	}
530     }
531 
532     if(searchsincelast) {
533 	vector<string> tnicks;
534 	insert_iterator< vector<string> > tins(tnicks, tnicks.begin());
535 
536 	set_difference(foundnicks.begin(), foundnicks.end(),
537 	    lastfoundnicks.begin(), lastfoundnicks.end(), tins);
538 
539 	lastfoundnicks = foundnicks;
540 	foundnicks = tnicks;
541 
542     } else {
543 	lastfoundnicks = foundnicks;
544 
545     }
546 
547     for(in = foundnicks.begin(); in != foundnicks.end(); ++in) {
548 	dnick = *in;
549 
550 	npos = 0;
551 
552 	if(!emailsub.empty()) npos = dnick.rfind("<"); else
553 	if(!namesub.empty()) npos =  dnick.rfind("[");
554 
555 	if(npos > 0) dnick.erase(npos-1);
556 
557 	c = new icqcontact(imcontact(dnick, irc));
558 	c->setdispnick(dnick);
559 
560 	searchdest->additem(conf->getcolor(cp_clist_irc), c, (string) " " + *in);
561 	foundguys.push_back(c);
562     }
563 
564     face.findready();
565     log(logConfMembers, foundguys.size());
566 
567     searchdest->redraw();
568     searchdest = 0;
569 }
570 
getautochannels() const571 vector<irchook::channelInfo> irchook::getautochannels() const {
572     vector<channelInfo> r;
573     vector<channelInfo>::const_iterator ic;
574 
575     for(ic = channels.begin(); ic != channels.end(); ++ic) {
576 	if(find(searchchannels.begin(), searchchannels.end(), ic->name) != searchchannels.end())
577 	    if(!ic->joined)
578 		// A channel used for search
579 		continue;
580 
581 	r.push_back(*ic);
582     }
583 
584     return r;
585 }
586 
setautochannels(vector<channelInfo> & achannels)587 void irchook::setautochannels(vector<channelInfo> &achannels) {
588     bool r;
589     vector<channelInfo>::iterator ic, iac;
590 
591     /*
592     *
593     * First, let's leave the channels we are not on anymore.
594     *
595     */
596 
597     for(ic = channels.begin(); ic != channels.end(); ++ic) {
598 	iac = find(achannels.begin(), achannels.end(), ic->name);
599 
600 	if(ic->joined) {
601 	    r = iac == achannels.end();
602 	    if(!r) r = !iac->joined;
603 	    if(r) firetalk_chat_part(irhook.handle, ic->name.c_str());
604 	}
605     }
606 
607     /*
608     *
609     * Now, let's see if there are any new channels we
610     * gotta join to.
611     *
612     */
613 
614     for(iac = achannels.begin(); iac != achannels.end(); ++iac) {
615 	ic = find(channels.begin(), channels.end(), iac->name);
616 
617 	if(iac->joined) {
618 	    r = ic == channels.end();
619 	    if(!r) r = !ic->joined;
620 	    string passname = iac->name;
621 	    if (!iac->passwd.empty())
622 	    	passname += " " + iac->passwd;
623 	    if(r) firetalk_chat_join(irhook.handle, passname.c_str());
624 	}
625     }
626 
627     channels = achannels;
628 }
629 
requestawaymsg(const imcontact & ic)630 void irchook::requestawaymsg(const imcontact &ic) {
631     em.store(imnotification(ic, string() +
632 	_("Away message:") + "\n\n" + awaymessages[ic.nickname]));
633 }
634 
rawcommand(const string & cmd)635 void irchook::rawcommand(const string &cmd) {
636     int *r, *w, *e, sock;
637     if(online()) {
638 	firetalk_getsockets(firetalk_find_protocol("IRC"), &r, &w, &e);
639 
640 	if(*r) {
641 	    write(*r, cmd.c_str(), cmd.size());
642 	    write(*r, "\n", 1);
643 	}
644 
645 	delete r;
646 	delete w;
647 	delete e;
648     }
649 }
650 
channelfatal(string room,const char * fmt,...)651 void irchook::channelfatal(string room, const char *fmt, ...) {
652     va_list ap;
653     char buf[NOTIFBUF];
654     vector<channelInfo>::iterator i;
655 
656     va_start(ap, fmt);
657     vsnprintf(buf, NOTIFBUF, fmt, ap);
658     va_end(ap);
659 
660     if(room.substr(0, 1) != "#")
661 	room.insert(0, "#");
662 
663     i = find(channels.begin(), channels.end(), room);
664 
665     if(i != channels.end()) {
666 	imcontact cont(room, irc);
667 	icqcontact *c = clist.get(cont);
668 	if(!c) c = clist.addnew(cont);
669 	c->setstatus(offline);
670 	i->joined = i->fetched = false;
671 	em.store(imnotification(cont, buf));
672     }
673 }
674 
ouridchanged(const icqconf::imaccount & ia)675 void irchook::ouridchanged(const icqconf::imaccount &ia) {
676     if(logged()) {
677 	firetalk_set_nickname(handle, ia.nickname.c_str());
678     }
679 }
680 
requestversion(const imcontact & c)681 void irchook::requestversion(const imcontact &c) {
682     if(logged()) {
683 	firetalk_subcode_send_request(handle, c.nickname.c_str(), "VERSION", 0);
684     }
685 }
686 
ping(const imcontact & c)687 void irchook::ping(const imcontact &c) {
688     if(logged()) {
689 	firetalk_subcode_send_request(handle, c.nickname.c_str(), "PING", 0);
690 	time(&pingtime[up(c.nickname)]);
691     }
692 }
693 
knowntransfer(const imfile & fr) const694 bool irchook::knowntransfer(const imfile &fr) const {
695     return transferinfo.find(fr) != transferinfo.end();
696 }
697 
replytransfer(const imfile & fr,bool accept,const string & localpath)698 void irchook::replytransfer(const imfile &fr, bool accept, const string &localpath) {
699     if(accept) {
700 	transferinfo[fr].second = localpath;
701 
702 	if(transferinfo[fr].second.substr(transferinfo[fr].second.size()-1) != "/")
703 	    transferinfo[fr].second += "/";
704 
705 	transferinfo[fr].second += justfname(fr.getfiles().begin()->fname);
706 
707 	firetalk_file_accept(handle, transferinfo[fr].first, 0,
708 	    transferinfo[fr].second.c_str());
709 
710     } else {
711 	firetalk_file_refuse(handle, transferinfo[fr].first);
712 	transferinfo.erase(fr);
713 
714     }
715 }
716 
aborttransfer(const imfile & fr)717 void irchook::aborttransfer(const imfile &fr) {
718     firetalk_file_cancel(handle, transferinfo[fr].first);
719 
720     face.transferupdate(fr.getfiles().begin()->fname, fr,
721 	icqface::tsCancel, 0, 0);
722 
723     irhook.transferinfo.erase(fr);
724 }
725 
getfevent(void * fhandle,imfile & fr)726 bool irchook::getfevent(void *fhandle, imfile &fr) {
727     map<imfile, pair<void *, string> >::const_iterator i = transferinfo.begin();
728 
729     while(i != transferinfo.end()) {
730 	if(i->second.first == fhandle) {
731 	    fr = i->first;
732 	    return true;
733 	}
734 	++i;
735     }
736 
737     return false;
738 }
739 
740 // ----------------------------------------------------------------------------
741 
userstatus(const string & nickname,imstatus st)742 void irchook::userstatus(const string &nickname, imstatus st) {
743     if(!nickname.empty()) {
744 	imcontact ic(nickname, irc);
745 	icqcontact *c = clist.get(ic);
746 
747 	if(c)
748 	if(st != c->getstatus()) {
749 	    logger.putonline(ic, c->getstatus(), st);
750 	    c->setstatus(st);
751 	}
752     }
753 }
754 
connected(void * conn,void * cli,...)755 void irchook::connected(void *conn, void *cli, ...) {
756     irhook.flogged = true;
757     irhook.log(logLogged);
758     face.update();
759 
760     int i;
761     vector<channelInfo>::iterator ic;
762     icqcontact *c;
763 
764     for(i = 0; i < clist.count; i++) {
765 	c = (icqcontact *) clist.at(i);
766 
767 	if(c->getdesc().pname == irc)
768 	if(!ischannel(c)) {
769 	    vector<icqgroup>::const_iterator ig = find(groups.begin(), groups.end(), clist.get(c)->getgroupid());
770 	    if(ig != groups.end()) {
771 	        firetalk_im_add_buddy(irhook.handle, c->getdesc().nickname.c_str() , ig->getname().c_str(), "");
772 	    }
773 	}
774     }
775 
776     for(ic = irhook.channels.begin(); ic != irhook.channels.end(); ++ic) {
777 	if(ic->joined) {
778 	    string passname = ic->name;
779 	    if (!ic->passwd.empty())
780 	    	passname += " " + ic->passwd;
781 	    firetalk_chat_join(irhook.handle, passname.c_str());
782 	}
783     }
784 
785     irhook.ourstatus = available;
786     irhook.setautostatus(irhook.manualstatus);
787     irhook.awaymessages.clear();
788     irhook.sentpass = false;
789 }
790 
disconnected(void * conn,void * cli,...)791 void irchook::disconnected(void *conn, void *cli, ...) {
792     irhook.fonline = false;
793 
794     logger.putourstatus(irc, irhook.getstatus(), offline);
795     clist.setoffline(irc);
796 
797     vector<channelInfo>::iterator ic;
798     for(ic = irhook.channels.begin(); ic != irhook.channels.end(); ++ic)
799 	ic->fetched = false;
800 
801     irhook.log(logDisconnected);
802     face.update();
803 }
804 
connectfailed(void * connection,void * cli,...)805 void irchook::connectfailed(void *connection, void *cli, ...) {
806     va_list ap;
807 
808     va_start(ap, cli);
809     int err = va_arg(ap, int);
810     char *reason = va_arg(ap, char *);
811     va_end(ap);
812 
813     irhook.fonline = false;
814 
815     face.log(_("+ [irc] connect failed: %s"), reason);
816     face.update();
817 }
818 
newnick(void * conn,void * cli,...)819 void irchook::newnick(void *conn, void *cli, ...) {
820     va_list ap;
821 
822     va_start(ap, cli);
823     char *nick = va_arg(ap, char *);
824     va_end(ap);
825 
826     if(nick)
827     if(strlen(nick)) {
828 	icqconf::imaccount acc = conf->getourid(irc);
829 	acc.nickname = nick;
830 	conf->setourid(acc);
831 
832 	face.log(_("+ [irc] nickname was changed successfully"));
833     }
834 }
835 
gotinfo(void * conn,void * cli,...)836 void irchook::gotinfo(void *conn, void *cli, ...) {
837     int pos;
838     va_list ap;
839     string about, email;
840     icqcontact::basicinfo cbinfo;
841 
842     va_start(ap, cli);
843     char *nick = va_arg(ap, char *);
844     char *info = va_arg(ap, char *);
845     int warning = va_arg(ap, int);
846     int idle = va_arg(ap, int);
847     va_end(ap);
848 
849     if(nick && info)
850     if(strlen(nick) && strlen(info)) {
851 	icqcontact *c = clist.get(imcontact(nick, irc));
852 
853 	if(!c) c = clist.get(contactroot);
854 
855 	about = info;
856 	cbinfo = c->getbasicinfo();
857 
858 	if((pos = about.find(":")) != -1) {
859 	    email = about.substr(0, pos);
860 	    about.erase(0, pos);
861 
862 	    if(email.substr(0, 1) == "~") email.erase(0, 1);
863 	    if((pos = about.find_first_not_of(" :")) > 0) about.erase(0, pos);
864 	}
865 
866 	cbinfo.lname = "";
867 	cbinfo.email = irhook.rushtmlconv("wk", email);
868 
869 	if((pos = about.find(" ")) != -1) {
870 	    cbinfo.lname = irhook.rushtmlconv("wk", about.substr(pos+1));
871 	    about.erase(pos);
872 	}
873 
874 	cbinfo.fname = irhook.rushtmlconv("wk", about);
875 
876 	c->setnick(nick);
877 	c->setbasicinfo(cbinfo);
878 
879 	if(c->getstatus() == offline)
880 	    c->setstatus(available);
881     }
882 }
883 
gotchannels(void * conn,void * cli,...)884 void irchook::gotchannels(void *conn, void *cli, ...) {
885     va_list ap;
886     string info;
887     icqcontact *c;
888 
889     va_start(ap, cli);
890     char *nick = va_arg(ap, char *);
891     char *channels = va_arg(ap, char *);
892     va_end(ap);
893 
894     if(nick && channels)
895     if(strlen(nick) && strlen(channels)) {
896 	c = clist.get(imcontact(nick, irc));
897 	if(!c) c = clist.get(contactroot);
898 
899 	c->setabout((string) _("On channels: ") + channels);
900 
901 	if(c->getstatus() == offline)
902 	    c->setstatus(available);
903     }
904 }
905 
getmessage(void * conn,void * cli,...)906 void irchook::getmessage(void *conn, void *cli, ...) {
907     va_list ap;
908 
909     va_start(ap, cli);
910     char *sender = va_arg(ap, char *);
911     int automessage_flag = va_arg(ap, int);
912     char *message = va_arg(ap, char *);
913     va_end(ap);
914 
915     if(sender && message)
916     if(strlen(sender) && strlen(message)) {
917 	/*if(!irhook.sentpass)  // NickServ identify should be handled by firetalk and needpass callback
918 	if(up(sender) == "NICKSERV") {
919 	    firetalk_im_send_message(irhook.handle, "NickServ",
920 		((string) "identify " + conf->getourid(irc).additional["nickpass"]).c_str(), 0);
921 
922 	    irhook.sentpass = true;
923 	}*/
924 
925 	em.store(immessage(imcontact(sender, irc),
926 	    imevent::incoming, irhook.rushtmlconv("wk", cuthtml(message, chCutBR | chLeaveLinks))));
927     }
928 }
929 
getaction(void * conn,void * cli,...)930 void irchook::getaction(void *conn, void *cli, ...) {
931     va_list ap;
932 
933     va_start(ap, cli);
934     char *sender = va_arg(ap, char *);
935     int automessage_flag = va_arg(ap, int);
936     char *message = va_arg(ap, char *);
937     va_end(ap);
938 
939     if(sender && message)
940     if(strlen(sender) && strlen(message)) {
941 	em.store(immessage(imcontact(sender, irc), imevent::incoming,
942 	    ((string) "* " + sender + " " +
943 		irhook.rushtmlconv("wk", cuthtml(message, chCutBR | chLeaveLinks))).c_str()));
944     }
945 }
946 
buddyonline(void * conn,void * cli,...)947 void irchook::buddyonline(void *conn, void *cli, ...) {
948     va_list ap;
949 
950     va_start(ap, cli);
951     char *nick = va_arg(ap, char *);
952     va_end(ap);
953 
954     if(nick)
955     if(strlen(nick)) {
956 	irhook.userstatus(nick, available);
957     }
958 }
959 
buddyoffline(void * conn,void * cli,...)960 void irchook::buddyoffline(void *conn, void *cli, ...) {
961     va_list ap;
962 
963     va_start(ap, cli);
964     char *nick = va_arg(ap, char *);
965     va_end(ap);
966 
967     if(nick)
968     if(strlen(nick)) {
969 	irhook.userstatus(nick, offline);
970     }
971 }
972 
buddyaway(void * conn,void * cli,...)973 void irchook::buddyaway(void *conn, void *cli, ...) {
974     va_list ap;
975 
976     va_start(ap, cli);
977     char *nick = va_arg(ap, char *);
978     char *msg = va_arg(ap, char *);
979     va_end(ap);
980 
981     if(nick)
982     if(strlen(nick)) {
983 	irhook.userstatus(nick, away);
984 	if(msg) irhook.awaymessages[nick] = irhook.rushtmlconv("wk", msg);
985     }
986 }
987 
listmember(void * connection,void * cli,...)988 void irchook::listmember(void *connection, void *cli, ...) {
989     va_list ap;
990     vector<channelInfo>::iterator ir;
991 
992     va_start(ap, cli);
993     char *room = va_arg(ap, char *);
994     char *membername = va_arg(ap, char *);
995     int opped = va_arg(ap, int);
996     va_end(ap);
997 
998     if(membername)
999     if(strlen(membername)) {
1000 	ir = find(irhook.channels.begin(), irhook.channels.end(), room);
1001 
1002 	if(ir != irhook.channels.end()) {
1003 	    ir->nicks.push_back(/*(string) (opped ? "@": "") +*/ membername);
1004 	}
1005     }
1006 }
1007 
fclog(void * connection,void * cli,...)1008 void irchook::fclog(void *connection, void *cli, ...) {
1009     va_list ap;
1010 
1011     va_start(ap, cli);
1012     char *msg = va_arg(ap, char *);
1013     va_end(ap);
1014 
1015     face.log("irc: %s", msg);
1016 }
1017 
chatnames(void * connection,void * cli,...)1018 void irchook::chatnames(void *connection, void *cli, ...) {
1019     va_list ap;
1020     vector<channelInfo>::iterator ic;
1021     vector<string>::iterator is;
1022     bool ready = true;
1023 
1024     va_start(ap, cli);
1025     char *croom = va_arg(ap, char *);
1026     va_end(ap);
1027 
1028     ic = find(irhook.channels.begin(), irhook.channels.end(), croom);
1029 
1030     if(ic != irhook.channels.end()) {
1031 	ic->fetched = true;
1032 	ic->nicks.clear();
1033 
1034 	if(irhook.searchdest) {
1035 	    if(irhook.emailsub.empty() && irhook.namesub.empty()) {
1036 		firetalk_chat_listmembers(irhook.handle, croom);
1037 		if(!ic->joined) firetalk_chat_part(irhook.handle, croom);
1038 	    } else {
1039 		firetalk_chat_requestextended(irhook.handle, croom);
1040 	    }
1041 	}
1042     }
1043 
1044     if(irhook.searchdest && irhook.emailsub.empty() && irhook.namesub.empty()) {
1045 	for(is = irhook.searchchannels.begin(); is != irhook.searchchannels.end(); ++is) {
1046 	    ic = find(irhook.channels.begin(), irhook.channels.end(), *is);
1047 
1048 	    if(ic != irhook.channels.end())
1049 	    if(!ic->fetched) {
1050 		ready = false;
1051 		break;
1052 	    }
1053 	}
1054 
1055 	if(ready) {
1056 	    irhook.processnicks();
1057 	}
1058     }
1059 }
1060 
listextended(void * connection,void * cli,...)1061 void irchook::listextended(void *connection, void *cli, ...) {
1062     va_list ap;
1063     string text, email, name;
1064     vector<channelInfo>::iterator ir;
1065     vector<string>::iterator is;
1066     int npos;
1067 
1068     va_start(ap, cli);
1069     char *nickname = va_arg(ap, char *);
1070     char *room = va_arg(ap, char *);
1071     char *login = va_arg(ap, char *);
1072     char *hostname = va_arg(ap, char *);
1073     char *net = va_arg(ap, char *);
1074     char *description = va_arg(ap, char *);
1075     va_end(ap);
1076 
1077     ir = find(irhook.channels.begin(), irhook.channels.end(), room);
1078 
1079     if(irhook.smode == Email) {
1080 	ir = find(irhook.channels.begin(), irhook.channels.end(), "");
1081 
1082 	if(ir == irhook.channels.end()) {
1083 	    irhook.channels.push_back(channelInfo(""));
1084 	    ir = irhook.channels.end()-1;
1085 	}
1086     }
1087 
1088     if(ir != irhook.channels.end()) {
1089 	name = description;
1090 	if((npos = name.find(" ")) != -1)
1091 	    name.erase(0, npos+1);
1092 
1093 	email = (string) login + "@" + hostname;
1094 
1095 	if(irhook.emailsub.empty() || email.find(irhook.emailsub) != -1 || irhook.smode == Email) {
1096 	    if(irhook.namesub.empty() || name.find(irhook.namesub) != -1) {
1097 		text = nickname;
1098 
1099 		if(!irhook.emailsub.empty()) {
1100 		    text += " <" + email + ">";
1101 		} else if(!irhook.namesub.empty()) {
1102 		    text += " [" + name + "]";
1103 		}
1104 
1105 		ir->nicks.push_back(text);
1106 	    }
1107 	}
1108     }
1109 
1110     if(find(irhook.extlisted.begin(), irhook.extlisted.end(), room) == irhook.extlisted.end())
1111 	irhook.extlisted.push_back(room);
1112 }
1113 
endextended(void * connection,void * cli,...)1114 void irchook::endextended(void *connection, void *cli, ...) {
1115     bool ready = true;
1116     vector<string>::iterator is;
1117     vector<channelInfo>::iterator ic;
1118 
1119     if(irhook.smode == Channel && !irhook.extlisted.empty()) {
1120 	ic = find(irhook.channels.begin(), irhook.channels.end(), irhook.extlisted.back());
1121 
1122 	if(ic != irhook.channels.end()) {
1123 	    if(!ic->joined)
1124 		firetalk_chat_part(irhook.handle, irhook.extlisted.back().c_str());
1125 
1126 	    for(is = irhook.searchchannels.begin(); ready && is != irhook.searchchannels.end(); ++is)
1127 		ready = find(irhook.extlisted.begin(), irhook.extlisted.end(), *is) != irhook.extlisted.end();
1128 	}
1129     }
1130 
1131     ready = ready || irhook.smode == Email;
1132 
1133     if(ready) {
1134 	irhook.processnicks();
1135 
1136 	if(irhook.smode == Email) {
1137 	    ic = find(irhook.channels.begin(), irhook.channels.end(), "");
1138 	    if(ic != irhook.channels.end()) irhook.channels.erase(ic);
1139 	}
1140     }
1141 }
1142 
chatmessage(void * connection,void * cli,...)1143 void irchook::chatmessage(void *connection, void *cli, ...) {
1144     va_list ap;
1145     string imsg;
1146 
1147     va_start(ap, cli);
1148     char *room = va_arg(ap, char *);
1149     char *from = va_arg(ap, char *);
1150     int automessage = va_arg(ap, int);
1151     char *msg = va_arg(ap, char *);
1152     va_end(ap);
1153 
1154     if(clist.get(imcontact(room, irc))) {
1155 	imsg = (string) from + ": " + msg;
1156 	getmessage(connection, cli, room, automessage, imsg.c_str());
1157     }
1158 }
1159 
chataction(void * connection,void * cli,...)1160 void irchook::chataction(void *connection, void *cli, ...) {
1161     va_list ap;
1162     string imsg;
1163 
1164     va_start(ap, cli);
1165     char *room = va_arg(ap, char *);
1166     char *from = va_arg(ap, char *);
1167     int automessage = va_arg(ap, int);
1168     char *msg = va_arg(ap, char *);
1169     va_end(ap);
1170 
1171     if(from && msg)
1172     if(strlen(from) && strlen(msg))
1173     if(clist.get(imcontact(room, irc))) {
1174 	em.store(immessage(imcontact(room, irc), imevent::incoming,
1175 	    ((string) "* " + from + " " +
1176 		irhook.rushtmlconv("wk", cuthtml(msg, chCutBR | chLeaveLinks))).c_str()));
1177     }
1178 }
1179 
1180 
chatjoined(void * connection,void * cli,...)1181 void irchook::chatjoined(void *connection, void *cli, ...) {
1182     va_list ap;
1183 
1184     va_start(ap, cli);
1185     char *room = va_arg(ap, char *);
1186     va_end(ap);
1187 
1188     icqcontact *c = clist.get(imcontact(room, irc));
1189     if(c) c->setstatus(available, false);
1190 }
1191 
chatleft(void * connection,void * cli,...)1192 void irchook::chatleft(void *connection, void *cli, ...) {
1193     va_list ap;
1194 
1195     va_start(ap, cli);
1196     char *room = va_arg(ap, char *);
1197     va_end(ap);
1198 
1199     icqcontact *c = clist.get(imcontact(room, irc));
1200     if(c) c->setstatus(offline, false);
1201 }
1202 
chatkicked(void * connection,void * cli,...)1203 void irchook::chatkicked(void *connection, void *cli, ...) {
1204     va_list ap;
1205 
1206     va_start(ap, cli);
1207     char *room = va_arg(ap, char *);
1208     char *by = va_arg(ap, char *);
1209     char *reason = va_arg(ap, char *);
1210     va_end(ap);
1211 
1212     irhook.channelfatal(room, _("Kicked by %s; reason: %s"),
1213 	by, irhook.rushtmlconv("wk", reason).c_str());
1214 }
1215 
errorhandler(void * connection,void * cli,...)1216 void irchook::errorhandler(void *connection, void *cli, ...) {
1217     va_list ap;
1218     icqcontact *c;
1219 
1220     va_start(ap, cli);
1221     int error = va_arg(ap, int);
1222     char *subject = va_arg(ap, char *);
1223     char *description = va_arg(ap, char *);
1224     va_end(ap);
1225 
1226     switch(error) {
1227 	case FE_ROOMUNAVAILABLE:
1228 	    // Cannot join channel
1229 	    if(subject)
1230 	    if(strlen(subject))
1231 		irhook.channelfatal(subject, "%s", description);
1232 	    break;
1233 	case FE_BADUSER:
1234 	    // Cannot fetch user's info
1235 	    if(subject)
1236 	    if(strlen(subject))
1237 	    if(c = clist.get(imcontact(subject, irc)))
1238 		c->setstatus(offline);
1239 	    break;
1240     }
1241 }
1242 
nickchanged(void * connection,void * cli,...)1243 void irchook::nickchanged(void *connection, void *cli, ...) {
1244     va_list ap;
1245     icqcontact *c;
1246     char buf[NOTIFBUF];
1247 
1248     va_start(ap, cli);
1249     char *oldnick = va_arg(ap, char *);
1250     char *newnick = va_arg(ap, char *);
1251     va_end(ap);
1252 
1253     if(oldnick && newnick)
1254     if(strcmp(oldnick, newnick)) {
1255 	if(c = clist.get(imcontact(oldnick, irc))) {
1256 	    if(!clist.get(imcontact(newnick, irc))) {
1257 		if(!c->inlist()) {
1258 		    if(c->getdispnick() == oldnick) c->setdispnick(newnick);
1259 		    c->setdesc(imcontact(newnick, irc));
1260 		    c->setnick(newnick);
1261 		}
1262 
1263 	    } else {
1264 		c->setstatus(offline);
1265 
1266 	    }
1267 
1268 	    snprintf(buf, NOTIFBUF, _("The user has changed their nick from %s to %s"), oldnick, newnick);
1269 	    em.store(imnotification(c, buf));
1270 	}
1271     }
1272 }
1273 
needpass(void * conn,void * cli,...)1274 void irchook::needpass(void *conn, void *cli, ...) {
1275     va_list ap;
1276 
1277     va_start(ap, cli);
1278     char *pass = va_arg(ap, char *);
1279     int size = va_arg(ap, int);
1280     va_end(ap);
1281 
1282     if(pass) {
1283 	icqconf::imaccount acc = conf->getourid(irc);
1284 
1285 	if (size == 129)  // signon password
1286 	{
1287 		if(!acc.password.empty()) {
1288 	    	strncpy(pass, acc.password.c_str(), size-1);
1289 	    	pass[size-1] = 0;
1290 	    	face.log(_("+ [irc] password sent"));
1291 		}
1292 	}
1293 	else // NickServ password
1294 	{
1295 		irhook.sentpass = true;
1296 		if(!acc.additional["nickpass"].empty()) {
1297 	    	strncpy(pass, acc.additional["nickpass"].c_str(), size-1);
1298 	    	pass[size-1] = 0;
1299 	    	face.log(_("+ [irc] nick password sent"));
1300 		}
1301 	}
1302     }
1303 }
1304 
subrequest(void * conn,void * cli,const char * const nick,const char * const command,const char * const args)1305 void irchook::subrequest(void *conn, void *cli, const char * const nick,
1306 const char * const command, const char * const args) {
1307 
1308     if(!strcmp(command, "VERSION")) {
1309 	ostringstream args_stream;
1310 	args_stream << PACKAGE << " " << centerim::version;
1311 	firetalk_subcode_send_reply(conn, nick, "VERSION", args_stream.str().c_str());
1312     }
1313 }
1314 
subreply(void * conn,void * cli,const char * const nick,const char * const command,const char * const args)1315 void irchook::subreply(void *conn, void *cli, const char * const nick,
1316 const char * const command, const char * const args) {
1317     char buf[NOTIFBUF];
1318 
1319     if(!strcmp(command, "PING")) {
1320 	map<string, time_t>::iterator i = irhook.pingtime.find(up(nick));
1321 
1322 	if(i != irhook.pingtime.end()) {
1323 	    snprintf(buf, NOTIFBUF, _("PING reply from the user: %d second(s)"), time(0)-i->second);
1324 	    em.store(imnotification(imcontact(nick, irc), buf));
1325 	}
1326 
1327     } else if(!strcmp(command, "VERSION")) {
1328 	snprintf(buf, NOTIFBUF, _("The remote is using %s"), args);
1329 	em.store(imnotification(imcontact(nick, irc), buf));
1330 
1331     }
1332 }
1333 
fileoffer(void * conn,void * cli,...)1334 void irchook::fileoffer(void *conn, void *cli, ...) {
1335     va_list ap;
1336 
1337     va_start(ap, cli);
1338     void *filehandle = va_arg(ap, void *);
1339     char *from = va_arg(ap, char *);
1340     char *filename = va_arg(ap, char *);
1341     long size = va_arg(ap, long);
1342     va_end(ap);
1343 
1344     imfile::record r;
1345     r.fname = filename;
1346     r.size = size;
1347 
1348     imfile fr(imcontact(from, irc), imevent::incoming, "",
1349 	vector<imfile::record>(1, r));
1350 
1351     irhook.transferinfo[fr].first = filehandle;
1352     em.store(fr);
1353 
1354     face.transferupdate(filename, fr, icqface::tsInit, size, 0);
1355 }
1356 
filestart(void * conn,void * cli,...)1357 void irchook::filestart(void *conn, void *cli, ...) {
1358     va_list ap;
1359     imfile fr;
1360 
1361     va_start(ap, cli);
1362     void *filehandle = va_arg(ap, void *);
1363     void *clientfilestruct = va_arg(ap, void *);
1364     va_end(ap);
1365 
1366     if(irhook.getfevent(filehandle, fr)) {
1367 	face.transferupdate(fr.getfiles().begin()->fname, fr,
1368 	    icqface::tsStart, 0, 0);
1369     }
1370 }
1371 
fileprogress(void * conn,void * cli,...)1372 void irchook::fileprogress(void *conn, void *cli, ...) {
1373     va_list ap;
1374     imfile fr;
1375 
1376     va_start(ap, cli);
1377     void *filehandle = va_arg(ap, void *);
1378     void *clientfilestruct = va_arg(ap, void *);
1379     long bytes = va_arg(ap, long);
1380     long size = va_arg(ap, long);
1381     va_end(ap);
1382 
1383     if(irhook.getfevent(filehandle, fr)) {
1384 	face.transferupdate(fr.getfiles().begin()->fname, fr,
1385 	    icqface::tsProgress, size, bytes);
1386     }
1387 }
1388 
filefinish(void * conn,void * cli,...)1389 void irchook::filefinish(void *conn, void *cli, ...) {
1390     va_list ap;
1391     imfile fr;
1392 
1393     va_start(ap, cli);
1394     void *filehandle = va_arg(ap, void *);
1395     void *clientfilestruct = va_arg(ap, void *);
1396     long size = va_arg(ap, long);
1397     va_end(ap);
1398 
1399     if(irhook.getfevent(filehandle, fr)) {
1400 	face.transferupdate(fr.getfiles().begin()->fname, fr,
1401 	    icqface::tsFinish, size, 0);
1402 
1403 	irhook.transferinfo.erase(fr);
1404     }
1405 }
1406 
fileerror(void * conn,void * cli,...)1407 void irchook::fileerror(void *conn, void *cli, ...) {
1408     va_list ap;
1409     imfile fr;
1410 
1411     va_start(ap, cli);
1412     void *filehandle = va_arg(ap, void *);
1413     void *clientfilestruct = va_arg(ap, void *);
1414     int error = va_arg(ap, int);
1415     va_end(ap);
1416 
1417     if(irhook.getfevent(filehandle, fr)) {
1418 	face.transferupdate(fr.getfiles().begin()->fname, fr,
1419 	    icqface::tsError, 0, 0);
1420 
1421 	irhook.transferinfo.erase(fr);
1422     }
1423 }
1424 
chatuserjoined(void * conn,void * cli,...)1425 void irchook::chatuserjoined(void *conn, void *cli, ...) {
1426     va_list ap;
1427 
1428     va_start(ap, cli);
1429     char *room = va_arg(ap, char *);
1430     char *who = va_arg(ap, char *);
1431     char *email = va_arg(ap, char *);
1432     va_end(ap);
1433 
1434     if(conf->getourid(irc).nickname != who) {
1435 	string uname = who;
1436 
1437 	if(email)
1438 	if(strlen(email))
1439 	    uname += (string) " (" + email + ")";
1440 
1441 	char buf[NOTIFBUF];
1442 	snprintf(buf, NOTIFBUF, _("%s has joined."), uname.c_str());
1443 	em.store(imnotification(imcontact(room, irc), buf));
1444     }
1445 }
1446 
chatuserleft(void * conn,void * cli,...)1447 void irchook::chatuserleft(void *conn, void *cli, ...) {
1448     va_list ap;
1449 
1450     va_start(ap, cli);
1451     char *room = va_arg(ap, char *);
1452     char *who = va_arg(ap, char *);
1453     char *reason = va_arg(ap, char *);
1454     va_end(ap);
1455 
1456     if(conf->getourid(irc).nickname != who) {
1457 	string text;
1458 	string text2;
1459 	char buf[NOTIFBUF];
1460 
1461 	snprintf(buf, NOTIFBUF, _("%s has left"), who); text = buf;
1462 
1463 	if(reason)
1464 	if(strlen(reason)) {
1465 	    if(strlen(reason) > 450) reason[450] = 0;
1466     	    text2 = irhook.rushtmlconv( "wk", reason );
1467 	    snprintf(buf, NOTIFBUF, _("reason: %s"), reason);
1468 	    text += (string) "; " + buf + ".";
1469 	}
1470 
1471 	em.store(imnotification(imcontact(room, irc), text));
1472     }
1473 }
1474 
chatuserkicked(void * conn,void * cli,...)1475 void irchook::chatuserkicked(void *conn, void *cli, ...) {
1476     va_list ap;
1477 
1478     va_start(ap, cli);
1479     char *room = va_arg(ap, char *);
1480     char *who = va_arg(ap, char *);
1481     char *by = va_arg(ap, char *);
1482     char *reason = va_arg(ap, char *);
1483     va_end(ap);
1484 
1485     if(conf->getourid(irc).nickname != who) {
1486 	string text;
1487 	char buf[NOTIFBUF];
1488 
1489 	snprintf(buf, NOTIFBUF, _("%s has been kicked by %s"), who, by); text = buf;
1490 
1491 	if(reason)
1492 	if(strlen(reason)) {
1493 	    snprintf(buf, NOTIFBUF, _("reason: %s"), reason);
1494 	    text += (string) "; " + buf + ".";
1495 	}
1496 
1497 	em.store(imnotification(imcontact(room, irc), text));
1498     }
1499 }
1500 
chatgottopic(void * conn,void * cli,...)1501 void irchook::chatgottopic(void *conn, void *cli, ...) {
1502     va_list ap;
1503 
1504     va_start(ap, cli);
1505     char *room = va_arg(ap, char *);
1506     char *topic = va_arg(ap, char *);
1507     char *author = va_arg(ap, char *);
1508     va_end(ap);
1509 
1510     vector<channelInfo>::const_iterator ic = find(irhook.channels.begin(), irhook.channels.end(), room);
1511 
1512     if(ic == irhook.channels.end() || !ic->joined)
1513 	return;
1514 
1515     string text;
1516     char buf[NOTIFBUF];
1517     text = irhook.rushtmlconv( "wk", topic );
1518     snprintf(buf, NOTIFBUF, _("Channel topic now is: %s"), text.c_str());
1519     text = buf;
1520 
1521     if(author)
1522     if(strlen(author)) {
1523 	snprintf(buf, NOTIFBUF, _("set by %s"), author);
1524 	text += (string) "; " + buf + ".";
1525     }
1526 
1527     em.store(imnotification(imcontact(room, irc), text));
1528 }
1529 
chatuseropped(void * conn,void * cli,...)1530 void irchook::chatuseropped(void *conn, void *cli, ...) {
1531     va_list ap;
1532 
1533     va_start(ap, cli);
1534     char *room = va_arg(ap, char *);
1535     char *who = va_arg(ap, char *);
1536     char *by = va_arg(ap, char *);
1537     va_end(ap);
1538 
1539     if(by) {
1540 	char buf[NOTIFBUF];
1541 	snprintf(buf, NOTIFBUF, _("%s has been opped by %s."), who, by);
1542 	em.store(imnotification(imcontact(room, irc), buf));
1543     }
1544 }
1545 
chatuserdeopped(void * conn,void * cli,...)1546 void irchook::chatuserdeopped(void *conn, void *cli, ...) {
1547     va_list ap;
1548 
1549     va_start(ap, cli);
1550     char *room = va_arg(ap, char *);
1551     char *who = va_arg(ap, char *);
1552     char *by = va_arg(ap, char *);
1553     va_end(ap);
1554 
1555     if(by) {
1556 	char buf[NOTIFBUF];
1557 	snprintf(buf, NOTIFBUF, _("%s has been deopped by %s."), who, by);
1558 	em.store(imnotification(imcontact(room, irc), buf));
1559     }
1560 }
1561 
chatopped(void * conn,void * cli,...)1562 void irchook::chatopped(void *conn, void *cli, ...) {
1563     va_list ap;
1564 
1565     va_start(ap, cli);
1566     char *room = va_arg(ap, char *);
1567     char *by = va_arg(ap, char *);
1568     va_end(ap);
1569 
1570     char buf[NOTIFBUF];
1571     if(by) snprintf(buf, NOTIFBUF, _("%s has opped us."), by);
1572 	else snprintf(buf, NOTIFBUF, _("you are an op here"));
1573     em.store(imnotification(imcontact(room, irc), buf));
1574 }
1575 
chatdeopped(void * conn,void * cli,...)1576 void irchook::chatdeopped(void *conn, void *cli, ...) {
1577     va_list ap;
1578 
1579     va_start(ap, cli);
1580     char *room = va_arg(ap, char *);
1581     char *by = va_arg(ap, char *);
1582     va_end(ap);
1583 
1584     char buf[NOTIFBUF];
1585     snprintf(buf, NOTIFBUF, _("%s has deopped us."), by);
1586     em.store(imnotification(imcontact(room, irc), buf));
1587 }
1588 
1589 // ----------------------------------------------------------------------------
1590 
operator !=(const string & aname) const1591 bool irchook::channelInfo::operator != (const string &aname) const {
1592     return up(aname) != up(name);
1593 }
1594 
operator ==(const string & aname) const1595 bool irchook::channelInfo::operator == (const string &aname) const {
1596     return up(aname) == up(name);
1597 }
1598 
1599 #endif
1600