3 * centerim IRC protocol handling class
4 * $Id: irchook.cc,v 1.80 2004/12/20 00:54:02 konst Exp $
6 * Copyright (C) 2001-2004 by Konstantin Klyagin <k@thekonst.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
29 #include "icqgroups.h"
31 #include "icqcontacts.h"
34 #include "accountmanager.h"
35 #include "eventmanager.h"
44 // ----------------------------------------------------------------------------
49 : abstracthook(irc
), handle(firetalk_create_handle(firetalk_find_protocol("IRC"), 0)),
50 fonline(false), flogged(false), ourstatus(offline
)
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
);
68 void irchook::init() {
71 manualstatus
= conf
->getstatus(irc
);
73 for(i
= 0; i
< clist
.count
; i
++) {
74 icqcontact
*c
= (icqcontact
*) clist
.at(i
);
76 if(c
->getdesc().pname
== irc
)
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
;
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
);
123 firetalk_subcode_register_request_callback(handle
, "VERSION", &subrequest
);
125 firetalk_subcode_register_reply_callback(handle
, "PING", &subreply
);
126 firetalk_subcode_register_reply_callback(handle
, "VERSION", &subreply
);
129 firetalk_register_callback(handle
, FC_LOG
, &fclog
);
132 void irchook::connect() {
133 icqconf::imaccount acc
= conf
->getourid(irc
);
136 firetalk_register_callback(handle
, FC_DISCONNECT
, 0);
137 firetalk_disconnect(handle
);
138 firetalk_register_callback(handle
, FC_DISCONNECT
, &disconnected
);
140 fonline
= firetalk_signon(handle
, acc
.server
.c_str(),
141 acc
.port
, acc
.nickname
.c_str()) == FE_SUCCESS
;
146 face
.log(_("+ [irc] unable to connect to the server"));
150 void irchook::disconnect() {
152 firetalk_disconnect(handle
);
156 void irchook::exectimers() {
159 void irchook::main() {
163 void irchook::getsockets(fd_set
&rfds
, fd_set
&wfds
, fd_set
&efds
, int &hsocket
) const {
164 int *r
, *w
, *e
, *sr
, *sw
, *se
;
166 firetalk_getsockets(firetalk_find_protocol("IRC"), &sr
, &sw
, &se
);
168 for(r
= sr
; *r
; r
++) {
169 if(*r
> hsocket
) hsocket
= *r
;
173 for(w
= sw
; *w
; w
++) {
174 if(*w
> hsocket
) hsocket
= *w
;
178 for(e
= se
; *e
; e
++) {
179 if(*e
> hsocket
) hsocket
= *e
;
188 bool irchook::isoursocket(fd_set
&rfds
, fd_set
&wfds
, fd_set
&efds
) const {
190 int *r
, *w
, *e
, *sr
, *sw
, *se
;
193 firetalk_getsockets(firetalk_find_protocol("IRC"), &sr
, &sw
, &se
);
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
);
207 bool irchook::online() const {
211 bool irchook::logged() const {
212 return flogged
&& fonline
;
215 bool irchook::enabled() const {
219 bool irchook::isconnecting() const {
220 return fonline
&& !flogged
;
223 bool irchook::send(const imevent
&ev
) {
224 icqcontact
*c
= clist
.get(ev
.getcontact());
229 if(ev
.gettype() == imevent::message
) {
230 const immessage
*m
= static_cast<const immessage
*>(&ev
);
231 text
= rusconv("kw", m
->gettext());
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());
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
;
242 for(ir
= files
.begin(); ir
!= files
.end(); ++ir
) {
247 imfile
fr(c
->getdesc(), imevent::outgoing
, "",
248 vector
<imfile::record
>(1, r
));
250 firetalk_file_offer(handle
, c
->getdesc().nickname
.c_str(),
251 ir
->fname
.c_str(), &transferinfo
[fr
].first
);
257 string original
= text
;
260 while (original
.length()>0)
262 if ((pos
= original
.find("\n")) != -1) // split by newlines into separate commands, drop empty ones
266 text
= original
.substr(0, pos
-1);
267 original
.erase(0, pos
+1);
271 original
.erase(0, pos
+1);
280 if(text
.substr(0, 1) == "/") {
282 cmd
= up(getword(text
));
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
;
290 } else if(cmd
== "KICK") {
291 text
= cmd
+ " " + c
->getdesc().nickname
+ " " + text
;
293 } else if(cmd
== "OP") {
294 text
= (string
) "mode " + c
->getdesc().nickname
+ " +o " + text
;
296 } else if(cmd
== "DEOP") {
297 text
= (string
) "mode " + c
->getdesc().nickname
+ " -o " + text
;
299 } else if(cmd
== "RAW") {
303 text
.insert(0, cmd
+ " ");
311 if (firetalk_chat_send_message(handle
,
312 c
->getdesc().nickname
.c_str(), text
.c_str(), 0) != FE_SUCCESS
)
316 if (firetalk_im_send_message(handle
,
317 c
->getdesc().nickname
.c_str(), text
.c_str(), 0) != FE_SUCCESS
)
328 void irchook::sendnewuser(const imcontact
&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(), "");
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
;
352 void irchook::removeuser(const imcontact
&ic
) {
355 firetalk_im_remove_buddy(handle
, ic
.nickname
.c_str());
357 vector
<channelInfo
> ch
= getautochannels();
358 vector
<channelInfo
>::iterator ich
= find(ch
.begin(), ch
.end(), ic
.nickname
);
359 if(ich
!= ch
.end()) {
367 void irchook::setautostatus(imstatus st
) {
369 if(getstatus() == offline
) {
372 if(getstatus() != st
) {
373 logger
.putourstatus(irc
, getstatus(), ourstatus
= st
);
380 firetalk_set_away(handle
, conf
->getawaymsg(irc
).c_str(), 0);
384 firetalk_set_away(handle
, 0, 0);
390 if(getstatus() != offline
) {
398 imstatus
irchook::getstatus() const {
399 return (flogged
&& fonline
) ? ourstatus
: offline
;
402 void irchook::requestinfo(const imcontact
&c
) {
403 firetalk_im_get_info(handle
, c
.nickname
.c_str());
406 void irchook::sendupdateuserinfo(icqcontact
&c
, const string
&newpass
) {
407 const icqcontact::basicinfo
&b
= c
.getbasicinfo();
410 if(!b
.lname
.empty()) {
411 if(!ircname
.empty()) ircname
+= " ";
416 void irchook::lookup(const imsearchparams
¶ms
, verticalmenu
&dest
) {
417 string rooms
= params
.room
, room
;
419 vector
<channelInfo
>::iterator ic
;
423 emailsub
= params
.email
;
424 namesub
= params
.firstname
;
425 searchsincelast
= params
.sincelast
&& !params
.room
.empty();
427 searchchannels
.clear();
430 while(!foundguys
.empty()) {
431 delete foundguys
.back();
432 foundguys
.pop_back();
435 if(!params
.room
.empty()) {
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
);
443 if(ic
== irhook
.channels
.end()) {
444 irhook
.channels
.push_back(channelInfo(room
));
445 ic
= irhook
.channels
.end()-1;
449 firetalk_chat_join(handle
, room
.c_str());
453 if(emailsub
.empty() && namesub
.empty()) {
454 /* if(ic->fetched) {*/
456 firetalk_chat_listmembers(handle
, room
.c_str());
465 firetalk_chat_requestextended(handle
, params
.room
.c_str());
474 } else if(!params
.email
.empty()) {
476 searchchannels
.push_back("");
477 firetalk_im_searchemail(handle
, ("*" + params
.email
+ "*").c_str());
482 void irchook::processnicks() {
485 vector
<string
> foundnicks
;
486 static vector
<string
> lastfoundnicks
;
487 vector
<string
>::iterator in
, isn
;
488 vector
<channelInfo
>::iterator ir
;
496 ir
= find(channels
.begin(), channels
.end(), *searchchannels
.begin());
497 if(ir
!= channels
.end())
498 foundnicks
= ir
->nicks
;
500 sort(foundnicks
.begin(), foundnicks
.end());
502 if(searchchannels
.size() > 1) {
503 for(in
= foundnicks
.begin(); in
!= foundnicks
.end(); ) {
506 for(ir
= channels
.begin(); !remove
&& (ir
!= channels
.end()); ++ir
) {
507 if(find(searchchannels
.begin(), searchchannels
.end(), ir
->name
) == searchchannels
.end())
509 if(ir
->name
== *searchchannels
.begin())
512 if(find(ir
->nicks
.begin(), ir
->nicks
.end(), *in
) == ir
->nicks
.end()) {
515 * Not found in one of other channels. Remove it from the
516 * first channel's list.
524 foundnicks
.erase(in
);
525 in
= foundnicks
.begin();
532 if(searchsincelast
) {
533 vector
<string
> tnicks
;
534 insert_iterator
< vector
<string
> > tins(tnicks
, tnicks
.begin());
536 set_difference(foundnicks
.begin(), foundnicks
.end(),
537 lastfoundnicks
.begin(), lastfoundnicks
.end(), tins
);
539 lastfoundnicks
= foundnicks
;
543 lastfoundnicks
= foundnicks
;
547 for(in
= foundnicks
.begin(); in
!= foundnicks
.end(); ++in
) {
552 if(!emailsub
.empty()) npos
= dnick
.rfind("<"); else
553 if(!namesub
.empty()) npos
= dnick
.rfind("[");
555 if(npos
> 0) dnick
.erase(npos
-1);
557 c
= new icqcontact(imcontact(dnick
, irc
));
558 c
->setdispnick(dnick
);
560 searchdest
->additem(conf
->getcolor(cp_clist_irc
), c
, (string
) " " + *in
);
561 foundguys
.push_back(c
);
565 log(logConfMembers
, foundguys
.size());
567 searchdest
->redraw();
571 vector
<irchook::channelInfo
> irchook::getautochannels() const {
572 vector
<channelInfo
> r
;
573 vector
<channelInfo
>::const_iterator ic
;
575 for(ic
= channels
.begin(); ic
!= channels
.end(); ++ic
) {
576 if(find(searchchannels
.begin(), searchchannels
.end(), ic
->name
) != searchchannels
.end())
578 // A channel used for search
587 void irchook::setautochannels(vector
<channelInfo
> &achannels
) {
589 vector
<channelInfo
>::iterator ic
, iac
;
593 * First, let's leave the channels we are not on anymore.
597 for(ic
= channels
.begin(); ic
!= channels
.end(); ++ic
) {
598 iac
= find(achannels
.begin(), achannels
.end(), ic
->name
);
601 r
= iac
== achannels
.end();
602 if(!r
) r
= !iac
->joined
;
603 if(r
) firetalk_chat_part(irhook
.handle
, ic
->name
.c_str());
609 * Now, let's see if there are any new channels we
614 for(iac
= achannels
.begin(); iac
!= achannels
.end(); ++iac
) {
615 ic
= find(channels
.begin(), channels
.end(), iac
->name
);
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());
627 channels
= achannels
;
630 void irchook::requestawaymsg(const imcontact
&ic
) {
631 em
.store(imnotification(ic
, string() +
632 _("Away message:") + "\n\n" + awaymessages
[ic
.nickname
]));
635 void irchook::rawcommand(const string
&cmd
) {
636 int *r
, *w
, *e
, sock
;
638 firetalk_getsockets(firetalk_find_protocol("IRC"), &r
, &w
, &e
);
641 write(*r
, cmd
.c_str(), cmd
.size());
651 void irchook::channelfatal(string room
, const char *fmt
, ...) {
654 vector
<channelInfo
>::iterator i
;
657 vsnprintf(buf
, NOTIFBUF
, fmt
, ap
);
660 if(room
.substr(0, 1) != "#")
663 i
= find(channels
.begin(), channels
.end(), room
);
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
));
675 void irchook::ouridchanged(const icqconf::imaccount
&ia
) {
677 firetalk_set_nickname(handle
, ia
.nickname
.c_str());
681 void irchook::requestversion(const imcontact
&c
) {
683 firetalk_subcode_send_request(handle
, c
.nickname
.c_str(), "VERSION", 0);
687 void irchook::ping(const imcontact
&c
) {
689 firetalk_subcode_send_request(handle
, c
.nickname
.c_str(), "PING", 0);
690 time(&pingtime
[up(c
.nickname
)]);
694 bool irchook::knowntransfer(const imfile
&fr
) const {
695 return transferinfo
.find(fr
) != transferinfo
.end();
698 void irchook::replytransfer(const imfile
&fr
, bool accept
, const string
&localpath
) {
700 transferinfo
[fr
].second
= localpath
;
702 if(transferinfo
[fr
].second
.substr(transferinfo
[fr
].second
.size()-1) != "/")
703 transferinfo
[fr
].second
+= "/";
705 transferinfo
[fr
].second
+= justfname(fr
.getfiles().begin()->fname
);
707 firetalk_file_accept(handle
, transferinfo
[fr
].first
, 0,
708 transferinfo
[fr
].second
.c_str());
711 firetalk_file_refuse(handle
, transferinfo
[fr
].first
);
712 transferinfo
.erase(fr
);
717 void irchook::aborttransfer(const imfile
&fr
) {
718 firetalk_file_cancel(handle
, transferinfo
[fr
].first
);
720 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
,
721 icqface::tsCancel
, 0, 0);
723 irhook
.transferinfo
.erase(fr
);
726 bool irchook::getfevent(void *fhandle
, imfile
&fr
) {
727 map
<imfile
, pair
<void *, string
> >::const_iterator i
= transferinfo
.begin();
729 while(i
!= transferinfo
.end()) {
730 if(i
->second
.first
== fhandle
) {
740 // ----------------------------------------------------------------------------
742 void irchook::userstatus(const string
&nickname
, imstatus st
) {
743 if(!nickname
.empty()) {
744 imcontact
ic(nickname
, irc
);
745 icqcontact
*c
= clist
.get(ic
);
748 if(st
!= c
->getstatus()) {
749 logger
.putonline(ic
, c
->getstatus(), st
);
755 void irchook::connected(void *conn
, void *cli
, ...) {
756 irhook
.flogged
= true;
757 irhook
.log(logLogged
);
761 vector
<channelInfo
>::iterator ic
;
764 for(i
= 0; i
< clist
.count
; i
++) {
765 c
= (icqcontact
*) clist
.at(i
);
767 if(c
->getdesc().pname
== irc
)
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(), "");
776 for(ic
= irhook
.channels
.begin(); ic
!= irhook
.channels
.end(); ++ic
) {
778 string passname
= ic
->name
;
779 if (!ic
->passwd
.empty())
780 passname
+= " " + ic
->passwd
;
781 firetalk_chat_join(irhook
.handle
, passname
.c_str());
785 irhook
.ourstatus
= available
;
786 irhook
.setautostatus(irhook
.manualstatus
);
787 irhook
.awaymessages
.clear();
788 irhook
.sentpass
= false;
791 void irchook::disconnected(void *conn
, void *cli
, ...) {
792 irhook
.fonline
= false;
794 logger
.putourstatus(irc
, irhook
.getstatus(), offline
);
795 clist
.setoffline(irc
);
797 vector
<channelInfo
>::iterator ic
;
798 for(ic
= irhook
.channels
.begin(); ic
!= irhook
.channels
.end(); ++ic
)
801 irhook
.log(logDisconnected
);
805 void irchook::connectfailed(void *connection
, void *cli
, ...) {
809 int err
= va_arg(ap
, int);
810 char *reason
= va_arg(ap
, char *);
813 irhook
.fonline
= false;
815 face
.log(_("+ [irc] connect failed: %s"), reason
);
819 void irchook::newnick(void *conn
, void *cli
, ...) {
823 char *nick
= va_arg(ap
, char *);
828 icqconf::imaccount acc
= conf
->getourid(irc
);
832 face
.log(_("+ [irc] nickname was changed successfully"));
836 void irchook::gotinfo(void *conn
, void *cli
, ...) {
840 icqcontact::basicinfo cbinfo
;
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);
850 if(strlen(nick
) && strlen(info
)) {
851 icqcontact
*c
= clist
.get(imcontact(nick
, irc
));
853 if(!c
) c
= clist
.get(contactroot
);
856 cbinfo
= c
->getbasicinfo();
858 if((pos
= about
.find(":")) != -1) {
859 email
= about
.substr(0, pos
);
862 if(email
.substr(0, 1) == "~") email
.erase(0, 1);
863 if((pos
= about
.find_first_not_of(" :")) > 0) about
.erase(0, pos
);
867 cbinfo
.email
= irhook
.rushtmlconv("wk", email
);
869 if((pos
= about
.find(" ")) != -1) {
870 cbinfo
.lname
= irhook
.rushtmlconv("wk", about
.substr(pos
+1));
874 cbinfo
.fname
= irhook
.rushtmlconv("wk", about
);
877 c
->setbasicinfo(cbinfo
);
879 if(c
->getstatus() == offline
)
880 c
->setstatus(available
);
884 void irchook::gotchannels(void *conn
, void *cli
, ...) {
890 char *nick
= va_arg(ap
, char *);
891 char *channels
= va_arg(ap
, char *);
895 if(strlen(nick
) && strlen(channels
)) {
896 c
= clist
.get(imcontact(nick
, irc
));
897 if(!c
) c
= clist
.get(contactroot
);
899 c
->setabout((string
) _("On channels: ") + channels
);
901 if(c
->getstatus() == offline
)
902 c
->setstatus(available
);
906 void irchook::getmessage(void *conn
, void *cli
, ...) {
910 char *sender
= va_arg(ap
, char *);
911 int automessage_flag
= va_arg(ap
, int);
912 char *message
= va_arg(ap
, char *);
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);
922 irhook.sentpass = true;
925 em
.store(immessage(imcontact(sender
, irc
),
926 imevent::incoming
, irhook
.rushtmlconv("wk", cuthtml(message
, chCutBR
| chLeaveLinks
))));
930 void irchook::getaction(void *conn
, void *cli
, ...) {
934 char *sender
= va_arg(ap
, char *);
935 int automessage_flag
= va_arg(ap
, int);
936 char *message
= va_arg(ap
, char *);
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()));
947 void irchook::buddyonline(void *conn
, void *cli
, ...) {
951 char *nick
= va_arg(ap
, char *);
956 irhook
.userstatus(nick
, available
);
960 void irchook::buddyoffline(void *conn
, void *cli
, ...) {
964 char *nick
= va_arg(ap
, char *);
969 irhook
.userstatus(nick
, offline
);
973 void irchook::buddyaway(void *conn
, void *cli
, ...) {
977 char *nick
= va_arg(ap
, char *);
978 char *msg
= va_arg(ap
, char *);
983 irhook
.userstatus(nick
, away
);
984 if(msg
) irhook
.awaymessages
[nick
] = irhook
.rushtmlconv("wk", msg
);
988 void irchook::listmember(void *connection
, void *cli
, ...) {
990 vector
<channelInfo
>::iterator ir
;
993 char *room
= va_arg(ap
, char *);
994 char *membername
= va_arg(ap
, char *);
995 int opped
= va_arg(ap
, int);
999 if(strlen(membername
)) {
1000 ir
= find(irhook
.channels
.begin(), irhook
.channels
.end(), room
);
1002 if(ir
!= irhook
.channels
.end()) {
1003 ir
->nicks
.push_back(/*(string) (opped ? "@": "") +*/ membername
);
1008 void irchook::fclog(void *connection
, void *cli
, ...) {
1012 char *msg
= va_arg(ap
, char *);
1015 face
.log("irc: %s", msg
);
1018 void irchook::chatnames(void *connection
, void *cli
, ...) {
1020 vector
<channelInfo
>::iterator ic
;
1021 vector
<string
>::iterator is
;
1025 char *croom
= va_arg(ap
, char *);
1028 ic
= find(irhook
.channels
.begin(), irhook
.channels
.end(), croom
);
1030 if(ic
!= irhook
.channels
.end()) {
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
);
1039 firetalk_chat_requestextended(irhook
.handle
, croom
);
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
);
1048 if(ic
!= irhook
.channels
.end())
1056 irhook
.processnicks();
1061 void irchook::listextended(void *connection
, void *cli
, ...) {
1063 string text
, email
, name
;
1064 vector
<channelInfo
>::iterator ir
;
1065 vector
<string
>::iterator is
;
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 *);
1077 ir
= find(irhook
.channels
.begin(), irhook
.channels
.end(), room
);
1079 if(irhook
.smode
== Email
) {
1080 ir
= find(irhook
.channels
.begin(), irhook
.channels
.end(), "");
1082 if(ir
== irhook
.channels
.end()) {
1083 irhook
.channels
.push_back(channelInfo(""));
1084 ir
= irhook
.channels
.end()-1;
1088 if(ir
!= irhook
.channels
.end()) {
1090 if((npos
= name
.find(" ")) != -1)
1091 name
.erase(0, npos
+1);
1093 email
= (string
) login
+ "@" + hostname
;
1095 if(irhook
.emailsub
.empty() || email
.find(irhook
.emailsub
) != -1 || irhook
.smode
== Email
) {
1096 if(irhook
.namesub
.empty() || name
.find(irhook
.namesub
) != -1) {
1099 if(!irhook
.emailsub
.empty()) {
1100 text
+= " <" + email
+ ">";
1101 } else if(!irhook
.namesub
.empty()) {
1102 text
+= " [" + name
+ "]";
1105 ir
->nicks
.push_back(text
);
1110 if(find(irhook
.extlisted
.begin(), irhook
.extlisted
.end(), room
) == irhook
.extlisted
.end())
1111 irhook
.extlisted
.push_back(room
);
1114 void irchook::endextended(void *connection
, void *cli
, ...) {
1116 vector
<string
>::iterator is
;
1117 vector
<channelInfo
>::iterator ic
;
1119 if(irhook
.smode
== Channel
&& !irhook
.extlisted
.empty()) {
1120 ic
= find(irhook
.channels
.begin(), irhook
.channels
.end(), irhook
.extlisted
.back());
1122 if(ic
!= irhook
.channels
.end()) {
1124 firetalk_chat_part(irhook
.handle
, irhook
.extlisted
.back().c_str());
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();
1131 ready
= ready
|| irhook
.smode
== Email
;
1134 irhook
.processnicks();
1136 if(irhook
.smode
== Email
) {
1137 ic
= find(irhook
.channels
.begin(), irhook
.channels
.end(), "");
1138 if(ic
!= irhook
.channels
.end()) irhook
.channels
.erase(ic
);
1143 void irchook::chatmessage(void *connection
, void *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 *);
1154 if(clist
.get(imcontact(room
, irc
))) {
1155 imsg
= (string
) from
+ ": " + msg
;
1156 getmessage(connection
, cli
, room
, automessage
, imsg
.c_str());
1160 void irchook::chataction(void *connection
, void *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 *);
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()));
1181 void irchook::chatjoined(void *connection
, void *cli
, ...) {
1185 char *room
= va_arg(ap
, char *);
1188 icqcontact
*c
= clist
.get(imcontact(room
, irc
));
1189 if(c
) c
->setstatus(available
, false);
1192 void irchook::chatleft(void *connection
, void *cli
, ...) {
1196 char *room
= va_arg(ap
, char *);
1199 icqcontact
*c
= clist
.get(imcontact(room
, irc
));
1200 if(c
) c
->setstatus(offline
, false);
1203 void irchook::chatkicked(void *connection
, void *cli
, ...) {
1207 char *room
= va_arg(ap
, char *);
1208 char *by
= va_arg(ap
, char *);
1209 char *reason
= va_arg(ap
, char *);
1212 irhook
.channelfatal(room
, _("Kicked by %s; reason: %s"),
1213 by
, irhook
.rushtmlconv("wk", reason
).c_str());
1216 void irchook::errorhandler(void *connection
, void *cli
, ...) {
1221 int error
= va_arg(ap
, int);
1222 char *subject
= va_arg(ap
, char *);
1223 char *description
= va_arg(ap
, char *);
1227 case FE_ROOMUNAVAILABLE
:
1228 // Cannot join channel
1231 irhook
.channelfatal(subject
, "%s", description
);
1234 // Cannot fetch user's info
1237 if(c
= clist
.get(imcontact(subject
, irc
)))
1238 c
->setstatus(offline
);
1243 void irchook::nickchanged(void *connection
, void *cli
, ...) {
1249 char *oldnick
= va_arg(ap
, char *);
1250 char *newnick
= va_arg(ap
, char *);
1253 if(oldnick
&& newnick
)
1254 if(strcmp(oldnick
, newnick
)) {
1255 if(c
= clist
.get(imcontact(oldnick
, irc
))) {
1256 if(!clist
.get(imcontact(newnick
, irc
))) {
1258 if(c
->getdispnick() == oldnick
) c
->setdispnick(newnick
);
1259 c
->setdesc(imcontact(newnick
, irc
));
1260 c
->setnick(newnick
);
1264 c
->setstatus(offline
);
1268 snprintf(buf
, NOTIFBUF
, _("The user has changed their nick from %s to %s"), oldnick
, newnick
);
1269 em
.store(imnotification(c
, buf
));
1274 void irchook::needpass(void *conn
, void *cli
, ...) {
1278 char *pass
= va_arg(ap
, char *);
1279 int size
= va_arg(ap
, int);
1283 icqconf::imaccount acc
= conf
->getourid(irc
);
1285 if (size
== 129) // signon password
1287 if(!acc
.password
.empty()) {
1288 strncpy(pass
, acc
.password
.c_str(), size
-1);
1290 face
.log(_("+ [irc] password sent"));
1293 else // NickServ password
1295 irhook
.sentpass
= true;
1296 if(!acc
.additional
["nickpass"].empty()) {
1297 strncpy(pass
, acc
.additional
["nickpass"].c_str(), size
-1);
1299 face
.log(_("+ [irc] nick password sent"));
1305 void irchook::subrequest(void *conn
, void *cli
, const char * const nick
,
1306 const char * const command
, const char * const args
) {
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());
1315 void irchook::subreply(void *conn
, void *cli
, const char * const nick
,
1316 const char * const command
, const char * const args
) {
1319 if(!strcmp(command
, "PING")) {
1320 map
<string
, time_t>::iterator i
= irhook
.pingtime
.find(up(nick
));
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
));
1327 } else if(!strcmp(command
, "VERSION")) {
1328 snprintf(buf
, NOTIFBUF
, _("The remote is using %s"), args
);
1329 em
.store(imnotification(imcontact(nick
, irc
), buf
));
1334 void irchook::fileoffer(void *conn
, void *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);
1348 imfile
fr(imcontact(from
, irc
), imevent::incoming
, "",
1349 vector
<imfile::record
>(1, r
));
1351 irhook
.transferinfo
[fr
].first
= filehandle
;
1354 face
.transferupdate(filename
, fr
, icqface::tsInit
, size
, 0);
1357 void irchook::filestart(void *conn
, void *cli
, ...) {
1362 void *filehandle
= va_arg(ap
, void *);
1363 void *clientfilestruct
= va_arg(ap
, void *);
1366 if(irhook
.getfevent(filehandle
, fr
)) {
1367 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
,
1368 icqface::tsStart
, 0, 0);
1372 void irchook::fileprogress(void *conn
, void *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);
1383 if(irhook
.getfevent(filehandle
, fr
)) {
1384 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
,
1385 icqface::tsProgress
, size
, bytes
);
1389 void irchook::filefinish(void *conn
, void *cli
, ...) {
1394 void *filehandle
= va_arg(ap
, void *);
1395 void *clientfilestruct
= va_arg(ap
, void *);
1396 long size
= va_arg(ap
, long);
1399 if(irhook
.getfevent(filehandle
, fr
)) {
1400 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
,
1401 icqface::tsFinish
, size
, 0);
1403 irhook
.transferinfo
.erase(fr
);
1407 void irchook::fileerror(void *conn
, void *cli
, ...) {
1412 void *filehandle
= va_arg(ap
, void *);
1413 void *clientfilestruct
= va_arg(ap
, void *);
1414 int error
= va_arg(ap
, int);
1417 if(irhook
.getfevent(filehandle
, fr
)) {
1418 face
.transferupdate(fr
.getfiles().begin()->fname
, fr
,
1419 icqface::tsError
, 0, 0);
1421 irhook
.transferinfo
.erase(fr
);
1425 void irchook::chatuserjoined(void *conn
, void *cli
, ...) {
1429 char *room
= va_arg(ap
, char *);
1430 char *who
= va_arg(ap
, char *);
1431 char *email
= va_arg(ap
, char *);
1434 if(conf
->getourid(irc
).nickname
!= who
) {
1439 uname
+= (string
) " (" + email
+ ")";
1442 snprintf(buf
, NOTIFBUF
, _("%s has joined."), uname
.c_str());
1443 em
.store(imnotification(imcontact(room
, irc
), buf
));
1447 void irchook::chatuserleft(void *conn
, void *cli
, ...) {
1451 char *room
= va_arg(ap
, char *);
1452 char *who
= va_arg(ap
, char *);
1453 char *reason
= va_arg(ap
, char *);
1456 if(conf
->getourid(irc
).nickname
!= who
) {
1461 snprintf(buf
, NOTIFBUF
, _("%s has left"), who
); text
= buf
;
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
+ ".";
1471 em
.store(imnotification(imcontact(room
, irc
), text
));
1475 void irchook::chatuserkicked(void *conn
, void *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 *);
1485 if(conf
->getourid(irc
).nickname
!= who
) {
1489 snprintf(buf
, NOTIFBUF
, _("%s has been kicked by %s"), who
, by
); text
= buf
;
1492 if(strlen(reason
)) {
1493 snprintf(buf
, NOTIFBUF
, _("reason: %s"), reason
);
1494 text
+= (string
) "; " + buf
+ ".";
1497 em
.store(imnotification(imcontact(room
, irc
), text
));
1501 void irchook::chatgottopic(void *conn
, void *cli
, ...) {
1505 char *room
= va_arg(ap
, char *);
1506 char *topic
= va_arg(ap
, char *);
1507 char *author
= va_arg(ap
, char *);
1510 vector
<channelInfo
>::const_iterator ic
= find(irhook
.channels
.begin(), irhook
.channels
.end(), room
);
1512 if(ic
== irhook
.channels
.end() || !ic
->joined
)
1517 text
= irhook
.rushtmlconv( "wk", topic
);
1518 snprintf(buf
, NOTIFBUF
, _("Channel topic now is: %s"), text
.c_str());
1522 if(strlen(author
)) {
1523 snprintf(buf
, NOTIFBUF
, _("set by %s"), author
);
1524 text
+= (string
) "; " + buf
+ ".";
1527 em
.store(imnotification(imcontact(room
, irc
), text
));
1530 void irchook::chatuseropped(void *conn
, void *cli
, ...) {
1534 char *room
= va_arg(ap
, char *);
1535 char *who
= va_arg(ap
, char *);
1536 char *by
= va_arg(ap
, char *);
1541 snprintf(buf
, NOTIFBUF
, _("%s has been opped by %s."), who
, by
);
1542 em
.store(imnotification(imcontact(room
, irc
), buf
));
1546 void irchook::chatuserdeopped(void *conn
, void *cli
, ...) {
1550 char *room
= va_arg(ap
, char *);
1551 char *who
= va_arg(ap
, char *);
1552 char *by
= va_arg(ap
, char *);
1557 snprintf(buf
, NOTIFBUF
, _("%s has been deopped by %s."), who
, by
);
1558 em
.store(imnotification(imcontact(room
, irc
), buf
));
1562 void irchook::chatopped(void *conn
, void *cli
, ...) {
1566 char *room
= va_arg(ap
, char *);
1567 char *by
= va_arg(ap
, char *);
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
));
1576 void irchook::chatdeopped(void *conn
, void *cli
, ...) {
1580 char *room
= va_arg(ap
, char *);
1581 char *by
= va_arg(ap
, char *);
1585 snprintf(buf
, NOTIFBUF
, _("%s has deopped us."), by
);
1586 em
.store(imnotification(imcontact(room
, irc
), buf
));
1589 // ----------------------------------------------------------------------------
1591 bool irchook::channelInfo::operator != (const string
&aname
) const {
1592 return up(aname
) != up(name
);
1595 bool irchook::channelInfo::operator == (const string
&aname
) const {
1596 return up(aname
) == up(name
);