Event backend porting, mostly WHOIS-related stuff
[quassel.git] / src / core / coresessioneventprocessor.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2010 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "coresessioneventprocessor.h"
22
23 #include "corenetwork.h"
24 #include "coresession.h"
25 #include "ircevent.h"
26 #include "ircuser.h"
27
28 CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session)
29   : QObject(session),
30   _coreSession(session)
31 {
32
33 }
34
35 bool CoreSessionEventProcessor::checkParamCount(IrcEvent *e, int minParams) {
36   if(e->params().count() < minParams) {
37     if(e->type() == EventManager::IrcEventNumeric) {
38       qWarning() << "Command " << static_cast<IrcEventNumeric *>(e)->number() << " requires " << minParams << "params, got: " << e->params();
39     } else {
40       QString name = coreSession()->eventManager()->enumName(e->type());
41       qWarning() << qPrintable(name) << "requires" << minParams << "params, got:" << e->params();
42     }
43     e->stop();
44     return false;
45   }
46   return true;
47 }
48
49 void CoreSessionEventProcessor::processIrcEventNumeric(IrcEventNumeric *e) {
50   switch(e->number()) {
51
52   // CAP stuff
53   case 903: case 904: case 905: case 906: case 907:
54     qobject_cast<CoreNetwork *>(e->network())->putRawLine("CAP END");
55     break;
56
57   default:
58     break;
59   }
60 }
61
62 void CoreSessionEventProcessor::processIrcEventAuthenticate(IrcEvent *e) {
63   if(!checkParamCount(e, 1))
64     return;
65
66   if(e->params().at(0) != "+") {
67     qWarning() << "Invalid AUTHENTICATE" << e;
68     return;
69   }
70
71   CoreNetwork *net = coreNetwork(e);
72
73   QString construct = net->saslAccount();
74   construct.append(QChar(QChar::Null));
75   construct.append(net->saslAccount());
76   construct.append(QChar(QChar::Null));
77   construct.append(net->saslPassword());
78   QByteArray saslData = QByteArray(construct.toAscii().toBase64());
79   saslData.prepend("AUTHENTICATE ");
80   net->putRawLine(saslData);
81 }
82
83 void CoreSessionEventProcessor::processIrcEventCap(IrcEvent *e) {
84   // for SASL, there will only be a single param of 'sasl', however you can check here for
85   // additional CAP messages (ls, multi-prefix, et cetera).
86
87   if(e->params().count() == 3) {
88     if(e->params().at(2) == "sasl") {
89       // FIXME use event
90       coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN")); // Only working with PLAIN atm, blowfish later
91     }
92   }
93 }
94
95 void CoreSessionEventProcessor::processIrcEventInvite(IrcEvent *e) {
96   if(checkParamCount(e, 2)) {
97     e->network()->updateNickFromMask(e->prefix());
98   }
99 }
100
101 void CoreSessionEventProcessor::processIrcEventKick(IrcEvent *e) {
102   if(checkParamCount(e, 2)) {
103     e->network()->updateNickFromMask(e->prefix());
104     IrcUser *victim = e->network()->ircUser(e->params().at(1));
105     if(victim) {
106       victim->partChannel(e->params().at(0));
107       //if(e->network()->isMe(victim)) e->network()->setKickedFromChannel(channel);
108     }
109   }
110 }
111
112 void CoreSessionEventProcessor::processIrcEventNick(IrcEvent *e) {
113   if(checkParamCount(e, 1)) {
114     IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
115     if(!ircuser) {
116       qWarning() << Q_FUNC_INFO << "Unknown IrcUser!";
117       return;
118     }
119     QString newnick = e->params().at(0);
120     QString oldnick = ircuser->nick();
121
122     // the order is cruicial
123     // otherwise the client would rename the buffer, see that the assigned ircuser doesn't match anymore
124     // and remove the ircuser from the querybuffer leading to a wrong on/offline state
125     ircuser->setNick(newnick);
126     coreSession()->renameBuffer(e->networkId(), newnick, oldnick);
127   }
128 }
129
130 void CoreSessionEventProcessor::processIrcEventPart(IrcEvent *e) {
131   if(checkParamCount(e, 1)) {
132     IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
133     if(!ircuser) {
134       qWarning() << Q_FUNC_INFO<< "Unknown IrcUser!";
135       return;
136     }
137     QString channel = e->params().at(0);
138     ircuser->partChannel(channel);
139     if(e->network()->isMe(ircuser))
140       qobject_cast<CoreNetwork *>(e->network())->setChannelParted(channel);
141   }
142 }
143
144 void CoreSessionEventProcessor::processIrcEventPong(IrcEvent *e) {
145   // the server is supposed to send back what we passed as param. and we send a timestamp
146   // but using quote and whatnought one can send arbitrary pings, so we have to do some sanity checks
147   if(checkParamCount(e, 2)) {
148     QString timestamp = e->params().at(1);
149     QTime sendTime = QTime::fromString(timestamp, "hh:mm:ss.zzz");
150     if(sendTime.isValid())
151       e->network()->setLatency(sendTime.msecsTo(QTime::currentTime()) / 2);
152   }
153 }
154
155 void CoreSessionEventProcessor::processIrcEventTopic(IrcEvent *e) {
156   if(checkParamCount(e, 2)) {
157     e->network()->updateNickFromMask(e->prefix());
158     IrcChannel *channel = e->network()->ircChannel(e->params().at(0));
159     if(channel)
160       channel->setTopic(e->params().at(1));
161   }
162 }
163
164 /* RPL_WELCOME */
165 void CoreSessionEventProcessor::processIrcEvent001(IrcEvent *e) {
166   if(!checkParamCount(e, 1))
167     return;
168
169   QString myhostmask = e->params().at(0).section(' ', -1, -1);
170   e->network()->setCurrentServer(e->prefix());
171   e->network()->setMyNick(nickFromMask(myhostmask));
172 }
173
174 /* RPL_UMODEIS - "<user_modes> [<user_mode_params>]" */
175 void CoreSessionEventProcessor::processIrcEvent221(IrcEvent *) {
176   // TODO: save information in network object
177 }
178
179 /* RPL_STATSCONN - "Highest connection cout: 8000 (7999 clients)" */
180 void CoreSessionEventProcessor::processIrcEvent250(IrcEvent *) {
181   // TODO: save information in network object
182 }
183
184 /* RPL_LOCALUSERS - "Current local user: 5024  Max: 7999 */
185 void CoreSessionEventProcessor::processIrcEvent265(IrcEvent *) {
186   // TODO: save information in network object
187 }
188
189 /* RPL_GLOBALUSERS - "Current global users: 46093  Max: 47650" */
190 void CoreSessionEventProcessor::processIrcEvent266(IrcEvent *) {
191   // TODO: save information in network object
192 }
193
194 /*
195 WHOIS-Message:
196    Replies 311 - 313, 317 - 319 are all replies generated in response to a WHOIS message.
197   and 301 (RPL_AWAY)
198               "<nick> :<away message>"
199 WHO-Message:
200    Replies 352 and 315 paired are used to answer a WHO message.
201
202 WHOWAS-Message:
203    Replies 314 and 369 are responses to a WHOWAS message.
204
205 */
206
207 /* RPL_AWAY - "<nick> :<away message>" */
208 void CoreSessionEventProcessor::processIrcEvent301(IrcEvent *e) {
209   if(!checkParamCount(e, 2))
210     return;
211
212   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
213   if(ircuser) {
214     ircuser->setAway(true);
215     ircuser->setAwayMessage(e->params().at(1));
216     //ircuser->setLastAwayMessage(now);
217   }
218 }
219
220 /* RPL_UNAWAY - ":You are no longer marked as being away" */
221 void CoreSessionEventProcessor::processIrcEvent305(IrcEvent *e) {
222   IrcUser *me = e->network()->me();
223   if(me)
224     me->setAway(false);
225
226   if(e->network()->autoAwayActive()) {
227     e->network()->setAutoAwayActive(false);
228     e->setFlag(EventManager::Silent);
229   }
230 }
231
232 /* RPL_NOWAWAY - ":You have been marked as being away" */
233 void CoreSessionEventProcessor::processIrcEvent306(IrcEvent *e) {
234   IrcUser *me = e->network()->me();
235   if(me)
236     me->setAway(true);
237 }
238
239 /* RPL_WHOISSERVICE - "<user> is registered nick" */
240 void CoreSessionEventProcessor::processIrcEvent307(IrcEvent *e) {
241   if(!checkParamCount(e, 1))
242     return;
243
244   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
245   if(ircuser)
246     ircuser->setWhoisServiceReply(e->params().join(" "));
247 }
248
249 /* RPL_SUSERHOST - "<user> is available for help." */
250 void CoreSessionEventProcessor::processIrcEvent310(IrcEvent *e) {
251   if(!checkParamCount(e, 1))
252     return;
253
254   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
255   if(ircuser)
256     ircuser->setSuserHost(e->params().join(" "));
257 }
258
259 /*  RPL_WHOISUSER - "<nick> <user> <host> * :<real name>" */
260 void CoreSessionEventProcessor::processIrcEvent311(IrcEvent *e) {
261   if(!checkParamCount(e, 3))
262     return;
263
264   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
265   if(ircuser) {
266     ircuser->setUser(e->params().at(1));
267     ircuser->setHost(e->params().at(2));
268     ircuser->setRealName(e->params().last());
269   }
270 }
271
272 /*  RPL_WHOISSERVER -  "<nick> <server> :<server info>" */
273 void CoreSessionEventProcessor::processIrcEvent312(IrcEvent *e) {
274   if(!checkParamCount(e, 2))
275     return;
276
277   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
278   if(ircuser)
279     ircuser->setServer(e->params().at(1));
280 }
281
282 /*  RPL_WHOISOPERATOR - "<nick> :is an IRC operator" */
283 void CoreSessionEventProcessor::processIrcEvent313(IrcEvent *e) {
284   if(!checkParamCount(e, 1))
285     return;
286
287   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
288   if(ircuser)
289     ircuser->setIrcOperator(e->params().last());
290 }
291
292 /*  RPL_ENDOFWHO: "<name> :End of WHO list" */
293 void CoreSessionEventProcessor::processIrcEvent315(IrcEvent *e) {
294   if(!checkParamCount(e, 1))
295     return;
296
297   if(coreNetwork(e)->setAutoWhoDone(e->params()[0]))
298     e->setFlag(EventManager::Silent);
299 }
300
301 /*  RPL_WHOISIDLE - "<nick> <integer> :seconds idle"
302    (real life: "<nick> <integer> <integer> :seconds idle, signon time) */
303 void CoreSessionEventProcessor::processIrcEvent317(IrcEvent *e) {
304   if(!checkParamCount(e, 2))
305     return;
306
307   QDateTime loginTime;
308
309   int idleSecs = e->params()[1].toInt();
310   if(e->params().count() > 3) { // if we have more then 3 params we have the above mentioned "real life" situation
311     int logintime = e->params()[2].toInt();
312     loginTime = QDateTime::fromTime_t(logintime);
313   }
314
315   IrcUser *ircuser = e->network()->ircUser(e->params()[0]);
316   if(ircuser) {
317     ircuser->setIdleTime(e->timestamp().addSecs(-idleSecs));
318     if(loginTime.isValid())
319       ircuser->setLoginTime(loginTime);
320   }
321 }
322
323
324
325 /* template
326 void CoreSessionEventProcessor::processIrcEvent(IrcEvent *e) {
327   if(!checkParamCount(e, 1))
328     return;
329
330 }
331 */