Event backend porting
[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 "coreirclisthelper.h"
24 #include "corenetwork.h"
25 #include "coresession.h"
26 #include "ircevent.h"
27 #include "ircuser.h"
28 #include "messageevent.h"
29 #include "netsplit.h"
30
31 CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session)
32   : QObject(session),
33   _coreSession(session)
34 {
35   connect(coreSession(), SIGNAL(networkDisconnected(NetworkId)), this, SLOT(destroyNetsplits(NetworkId)));
36 }
37
38 bool CoreSessionEventProcessor::checkParamCount(IrcEvent *e, int minParams) {
39   if(e->params().count() < minParams) {
40     if(e->type() == EventManager::IrcEventNumeric) {
41       qWarning() << "Command " << static_cast<IrcEventNumeric *>(e)->number() << " requires " << minParams << "params, got: " << e->params();
42     } else {
43       QString name = coreSession()->eventManager()->enumName(e->type());
44       qWarning() << qPrintable(name) << "requires" << minParams << "params, got:" << e->params();
45     }
46     e->stop();
47     return false;
48   }
49   return true;
50 }
51
52 void CoreSessionEventProcessor::tryNextNick(NetworkEvent *e, const QString &errnick, bool erroneus) {
53   QStringList desiredNicks = coreSession()->identity(e->network()->identity())->nicks();
54   int nextNickIdx = desiredNicks.indexOf(errnick) + 1;
55   QString nextNick;
56   if(nextNickIdx > 0 && desiredNicks.size() > nextNickIdx) {
57     nextNick = desiredNicks[nextNickIdx];
58   } else {
59     if(erroneus) {
60       // FIXME Make this an ErrorEvent or something like that, so it's translated in the client
61       MessageEvent *msgEvent = new MessageEvent(Message::Error, e->network(),
62                                                 tr("No free and valid nicks in nicklist found. use: /nick <othernick> to continue"),
63                                                 QString(), QString(), Message::None, e->timestamp());
64       coreSession()->eventManager()->sendEvent(msgEvent);
65       return;
66     } else {
67       nextNick = errnick + "_";
68     }
69   }
70   // FIXME Use a proper output event for this
71   coreNetwork(e)->putRawLine("NICK " + coreNetwork(e)->encodeServerString(nextNick));
72 }
73
74 void CoreSessionEventProcessor::processIrcEventNumeric(IrcEventNumeric *e) {
75   switch(e->number()) {
76
77   // CAP stuff
78   case 903: case 904: case 905: case 906: case 907:
79     qobject_cast<CoreNetwork *>(e->network())->putRawLine("CAP END");
80     break;
81
82   default:
83     break;
84   }
85 }
86
87 void CoreSessionEventProcessor::processIrcEventAuthenticate(IrcEvent *e) {
88   if(!checkParamCount(e, 1))
89     return;
90
91   if(e->params().at(0) != "+") {
92     qWarning() << "Invalid AUTHENTICATE" << e;
93     return;
94   }
95
96   CoreNetwork *net = coreNetwork(e);
97
98   QString construct = net->saslAccount();
99   construct.append(QChar(QChar::Null));
100   construct.append(net->saslAccount());
101   construct.append(QChar(QChar::Null));
102   construct.append(net->saslPassword());
103   QByteArray saslData = QByteArray(construct.toAscii().toBase64());
104   saslData.prepend("AUTHENTICATE ");
105   net->putRawLine(saslData);
106 }
107
108 void CoreSessionEventProcessor::processIrcEventCap(IrcEvent *e) {
109   // for SASL, there will only be a single param of 'sasl', however you can check here for
110   // additional CAP messages (ls, multi-prefix, et cetera).
111
112   if(e->params().count() == 3) {
113     if(e->params().at(2) == "sasl") {
114       // FIXME use event
115       coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN")); // Only working with PLAIN atm, blowfish later
116     }
117   }
118 }
119
120 void CoreSessionEventProcessor::processIrcEventInvite(IrcEvent *e) {
121   if(checkParamCount(e, 2)) {
122     e->network()->updateNickFromMask(e->prefix());
123   }
124 }
125
126 void CoreSessionEventProcessor::processIrcEventJoin(IrcEvent *e) {
127   if(e->testFlag(EventManager::Fake)) // generated by handleEarlyNetsplitJoin
128     return;
129
130   if(!checkParamCount(e, 1))
131     return;
132
133   CoreNetwork *net = coreNetwork(e);
134   QString channel = e->params()[0];
135   IrcUser *ircuser = net->updateNickFromMask(e->prefix());
136
137   bool handledByNetsplit = false;
138   foreach(Netsplit* n, _netsplits.value(e->network())) {
139     handledByNetsplit = n->userJoined(e->prefix(), channel);
140     if(handledByNetsplit)
141       break;
142   }
143
144   if(!handledByNetsplit)
145     ircuser->joinChannel(channel);
146   else
147     e->setFlag(EventManager::Netsplit);
148
149   if(net->isMe(ircuser)) {
150     net->setChannelJoined(channel);
151      // FIXME use event
152     net->putRawLine(net->serverEncode("MODE " + channel)); // we want to know the modes of the channel we just joined, so we ask politely
153   }
154 }
155
156 void CoreSessionEventProcessor::processIrcEventKick(IrcEvent *e) {
157   if(checkParamCount(e, 2)) {
158     e->network()->updateNickFromMask(e->prefix());
159     IrcUser *victim = e->network()->ircUser(e->params().at(1));
160     if(victim) {
161       victim->partChannel(e->params().at(0));
162       //if(e->network()->isMe(victim)) e->network()->setKickedFromChannel(channel);
163     }
164   }
165 }
166
167 void CoreSessionEventProcessor::processIrcEventMode(IrcEvent *e) {
168   if(!checkParamCount(e, 2))
169     return;
170
171   if(e->network()->isChannelName(e->params().first())) {
172     // Channel Modes
173
174     IrcChannel *channel = e->network()->ircChannel(e->params()[0]);
175     if(!channel) {
176       // we received mode information for a channel we're not in. that means probably we've just been kicked out or something like that
177       // anyways: we don't have a place to store the data --> discard the info.
178       return;
179     }
180
181     QString modes = e->params()[1];
182     bool add = true;
183     int paramOffset = 2;
184     for(int c = 0; c < modes.length(); c++) {
185       if(modes[c] == '+') {
186         add = true;
187         continue;
188       }
189       if(modes[c] == '-') {
190         add = false;
191         continue;
192       }
193
194       if(e->network()->prefixModes().contains(modes[c])) {
195         // user channel modes (op, voice, etc...)
196         if(paramOffset < e->params().count()) {
197           IrcUser *ircUser = e->network()->ircUser(e->params()[paramOffset]);
198           if(!ircUser) {
199             qWarning() << Q_FUNC_INFO << "Unknown IrcUser:" << e->params()[paramOffset];
200           } else {
201             if(add) {
202               bool handledByNetsplit = false;
203               QHash<QString, Netsplit *> splits = _netsplits.value(e->network());
204               foreach(Netsplit* n, _netsplits.value(e->network())) {
205                 handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name());
206                 if(handledByNetsplit) {
207                   n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c]));
208                   break;
209                 }
210               }
211               if(!handledByNetsplit)
212                 channel->addUserMode(ircUser, QString(modes[c]));
213             }
214             else
215               channel->removeUserMode(ircUser, QString(modes[c]));
216           }
217         } else {
218           qWarning() << "Received MODE with too few parameters:" << e->params();
219         }
220         ++paramOffset;
221       } else {
222         // regular channel modes
223         QString value;
224         Network::ChannelModeType modeType = e->network()->channelModeType(modes[c]);
225         if(modeType == Network::A_CHANMODE || modeType == Network::B_CHANMODE || (modeType == Network::C_CHANMODE && add)) {
226           if(paramOffset < e->params().count()) {
227             value = e->params()[paramOffset];
228           } else {
229             qWarning() << "Received MODE with too few parameters:" << e->params();
230           }
231           ++paramOffset;
232         }
233
234         if(add)
235           channel->addChannelMode(modes[c], value);
236         else
237           channel->removeChannelMode(modes[c], value);
238       }
239     }
240
241   } else {
242     // pure User Modes
243     IrcUser *ircUser = e->network()->newIrcUser(e->params().first());
244     QString modeString(e->params()[1]);
245     QString addModes;
246     QString removeModes;
247     bool add = false;
248     for(int c = 0; c < modeString.count(); c++) {
249       if(modeString[c] == '+') {
250         add = true;
251         continue;
252       }
253       if(modeString[c] == '-') {
254         add = false;
255         continue;
256       }
257       if(add)
258         addModes += modeString[c];
259       else
260         removeModes += modeString[c];
261     }
262     if(!addModes.isEmpty())
263       ircUser->addUserModes(addModes);
264     if(!removeModes.isEmpty())
265       ircUser->removeUserModes(removeModes);
266
267     if(e->network()->isMe(ircUser)) {
268       coreNetwork(e)->updatePersistentModes(addModes, removeModes);
269     }
270   }
271 }
272
273 void CoreSessionEventProcessor::processIrcEventNick(IrcEvent *e) {
274   if(checkParamCount(e, 1)) {
275     IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
276     if(!ircuser) {
277       qWarning() << Q_FUNC_INFO << "Unknown IrcUser!";
278       return;
279     }
280     QString newnick = e->params().at(0);
281     QString oldnick = ircuser->nick();
282
283     // the order is cruicial
284     // otherwise the client would rename the buffer, see that the assigned ircuser doesn't match anymore
285     // and remove the ircuser from the querybuffer leading to a wrong on/offline state
286     ircuser->setNick(newnick);
287     coreSession()->renameBuffer(e->networkId(), newnick, oldnick);
288   }
289 }
290
291 void CoreSessionEventProcessor::processIrcEventPart(IrcEvent *e) {
292   if(checkParamCount(e, 1)) {
293     IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
294     if(!ircuser) {
295       qWarning() << Q_FUNC_INFO<< "Unknown IrcUser!";
296       return;
297     }
298     QString channel = e->params().at(0);
299     ircuser->partChannel(channel);
300     if(e->network()->isMe(ircuser))
301       qobject_cast<CoreNetwork *>(e->network())->setChannelParted(channel);
302   }
303 }
304
305 void CoreSessionEventProcessor::processIrcEventPong(IrcEvent *e) {
306   // the server is supposed to send back what we passed as param. and we send a timestamp
307   // but using quote and whatnought one can send arbitrary pings, so we have to do some sanity checks
308   if(checkParamCount(e, 2)) {
309     QString timestamp = e->params().at(1);
310     QTime sendTime = QTime::fromString(timestamp, "hh:mm:ss.zzz");
311     if(sendTime.isValid())
312       e->network()->setLatency(sendTime.msecsTo(QTime::currentTime()) / 2);
313   }
314 }
315
316 void CoreSessionEventProcessor::processIrcEventQuit(IrcEvent *e) {
317   IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
318   if(!ircuser)
319     return;
320
321   QString msg;
322   if(e->params().count() > 0)
323     msg = e->params()[0];
324
325   // check if netsplit
326   if(Netsplit::isNetsplit(msg)) {
327     Netsplit *n;
328     if(!_netsplits[e->network()].contains(msg)) {
329       n = new Netsplit(e->network(), this);
330       connect(n, SIGNAL(finished()), this, SLOT(handleNetsplitFinished()));
331       connect(n, SIGNAL(netsplitJoin(Network*,QString,QStringList,QStringList,QString)),
332               this, SLOT(handleNetsplitJoin(Network*,QString,QStringList,QStringList,QString)));
333       connect(n, SIGNAL(netsplitQuit(Network*,QString,QStringList,QString)),
334               this, SLOT(handleNetsplitQuit(Network*,QString,QStringList,QString)));
335       connect(n, SIGNAL(earlyJoin(Network*,QString,QStringList,QStringList)),
336               this, SLOT(handleEarlyNetsplitJoin(Network*,QString,QStringList,QStringList)));
337       _netsplits[e->network()].insert(msg, n);
338     }
339     else {
340       n = _netsplits[e->network()][msg];
341     }
342     // add this user to the netsplit
343     n->userQuit(e->prefix(), ircuser->channels(), msg);
344     e->setFlag(EventManager::Netsplit);
345   }
346   // normal quit is handled in lateProcessIrcEventQuit()
347 }
348
349 void CoreSessionEventProcessor::lateProcessIrcEventQuit(IrcEvent *e) {
350   if(e->testFlag(EventManager::Netsplit))
351     return;
352
353   IrcUser *ircuser = e->network()->updateNickFromMask(e->prefix());
354   if(!ircuser)
355     return;
356
357   ircuser->quit();
358 }
359
360 void CoreSessionEventProcessor::processIrcEventTopic(IrcEvent *e) {
361   if(checkParamCount(e, 2)) {
362     e->network()->updateNickFromMask(e->prefix());
363     IrcChannel *channel = e->network()->ircChannel(e->params().at(0));
364     if(channel)
365       channel->setTopic(e->params().at(1));
366   }
367 }
368
369 /* RPL_WELCOME */
370 void CoreSessionEventProcessor::processIrcEvent001(IrcEvent *e) {
371   if(!checkParamCount(e, 1))
372     return;
373
374   QString myhostmask = e->params().at(0).section(' ', -1, -1);
375   e->network()->setCurrentServer(e->prefix());
376   e->network()->setMyNick(nickFromMask(myhostmask));
377 }
378
379 /* RPL_ISUPPORT */
380 // TODO Complete 005 handling, also use sensible defaults for non-sent stuff
381 void CoreSessionEventProcessor::processIrcEvent005(IrcEvent *e) {
382   if(!checkParamCount(e, 1))
383     return;
384
385   QString key, value;
386   for(int i = 0; i < e->params().count() - 1; i++) {
387     QString key = e->params()[i].section("=", 0, 0);
388     QString value = e->params()[i].section("=", 1);
389     e->network()->addSupport(key, value);
390   }
391
392   /* determine our prefixes here to get an accurate result */
393   e->network()->determinePrefixes();
394 }
395
396 /* RPL_UMODEIS - "<user_modes> [<user_mode_params>]" */
397 void CoreSessionEventProcessor::processIrcEvent221(IrcEvent *) {
398   // TODO: save information in network object
399 }
400
401 /* RPL_STATSCONN - "Highest connection cout: 8000 (7999 clients)" */
402 void CoreSessionEventProcessor::processIrcEvent250(IrcEvent *) {
403   // TODO: save information in network object
404 }
405
406 /* RPL_LOCALUSERS - "Current local user: 5024  Max: 7999 */
407 void CoreSessionEventProcessor::processIrcEvent265(IrcEvent *) {
408   // TODO: save information in network object
409 }
410
411 /* RPL_GLOBALUSERS - "Current global users: 46093  Max: 47650" */
412 void CoreSessionEventProcessor::processIrcEvent266(IrcEvent *) {
413   // TODO: save information in network object
414 }
415
416 /*
417 WHOIS-Message:
418    Replies 311 - 313, 317 - 319 are all replies generated in response to a WHOIS message.
419   and 301 (RPL_AWAY)
420               "<nick> :<away message>"
421 WHO-Message:
422    Replies 352 and 315 paired are used to answer a WHO message.
423
424 WHOWAS-Message:
425    Replies 314 and 369 are responses to a WHOWAS message.
426
427 */
428
429 /* RPL_AWAY - "<nick> :<away message>" */
430 void CoreSessionEventProcessor::processIrcEvent301(IrcEvent *e) {
431   if(!checkParamCount(e, 2))
432     return;
433
434   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
435   if(ircuser) {
436     ircuser->setAway(true);
437     ircuser->setAwayMessage(e->params().at(1));
438     //ircuser->setLastAwayMessage(now);
439   }
440 }
441
442 /* RPL_UNAWAY - ":You are no longer marked as being away" */
443 void CoreSessionEventProcessor::processIrcEvent305(IrcEvent *e) {
444   IrcUser *me = e->network()->me();
445   if(me)
446     me->setAway(false);
447
448   if(e->network()->autoAwayActive()) {
449     e->network()->setAutoAwayActive(false);
450     e->setFlag(EventManager::Silent);
451   }
452 }
453
454 /* RPL_NOWAWAY - ":You have been marked as being away" */
455 void CoreSessionEventProcessor::processIrcEvent306(IrcEvent *e) {
456   IrcUser *me = e->network()->me();
457   if(me)
458     me->setAway(true);
459 }
460
461 /* RPL_WHOISSERVICE - "<user> is registered nick" */
462 void CoreSessionEventProcessor::processIrcEvent307(IrcEvent *e) {
463   if(!checkParamCount(e, 1))
464     return;
465
466   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
467   if(ircuser)
468     ircuser->setWhoisServiceReply(e->params().join(" "));
469 }
470
471 /* RPL_SUSERHOST - "<user> is available for help." */
472 void CoreSessionEventProcessor::processIrcEvent310(IrcEvent *e) {
473   if(!checkParamCount(e, 1))
474     return;
475
476   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
477   if(ircuser)
478     ircuser->setSuserHost(e->params().join(" "));
479 }
480
481 /*  RPL_WHOISUSER - "<nick> <user> <host> * :<real name>" */
482 void CoreSessionEventProcessor::processIrcEvent311(IrcEvent *e) {
483   if(!checkParamCount(e, 3))
484     return;
485
486   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
487   if(ircuser) {
488     ircuser->setUser(e->params().at(1));
489     ircuser->setHost(e->params().at(2));
490     ircuser->setRealName(e->params().last());
491   }
492 }
493
494 /*  RPL_WHOISSERVER -  "<nick> <server> :<server info>" */
495 void CoreSessionEventProcessor::processIrcEvent312(IrcEvent *e) {
496   if(!checkParamCount(e, 2))
497     return;
498
499   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
500   if(ircuser)
501     ircuser->setServer(e->params().at(1));
502 }
503
504 /*  RPL_WHOISOPERATOR - "<nick> :is an IRC operator" */
505 void CoreSessionEventProcessor::processIrcEvent313(IrcEvent *e) {
506   if(!checkParamCount(e, 1))
507     return;
508
509   IrcUser *ircuser = e->network()->ircUser(e->params().at(0));
510   if(ircuser)
511     ircuser->setIrcOperator(e->params().last());
512 }
513
514 /*  RPL_ENDOFWHO: "<name> :End of WHO list" */
515 void CoreSessionEventProcessor::processIrcEvent315(IrcEvent *e) {
516   if(!checkParamCount(e, 1))
517     return;
518
519   if(coreNetwork(e)->setAutoWhoDone(e->params()[0]))
520     e->setFlag(EventManager::Silent);
521 }
522
523 /*  RPL_WHOISIDLE - "<nick> <integer> :seconds idle"
524    (real life: "<nick> <integer> <integer> :seconds idle, signon time) */
525 void CoreSessionEventProcessor::processIrcEvent317(IrcEvent *e) {
526   if(!checkParamCount(e, 2))
527     return;
528
529   QDateTime loginTime;
530
531   int idleSecs = e->params()[1].toInt();
532   if(e->params().count() > 3) { // if we have more then 3 params we have the above mentioned "real life" situation
533     int logintime = e->params()[2].toInt();
534     loginTime = QDateTime::fromTime_t(logintime);
535   }
536
537   IrcUser *ircuser = e->network()->ircUser(e->params()[0]);
538   if(ircuser) {
539     ircuser->setIdleTime(e->timestamp().addSecs(-idleSecs));
540     if(loginTime.isValid())
541       ircuser->setLoginTime(loginTime);
542   }
543 }
544
545 /* RPL_LIST -  "<channel> <# visible> :<topic>" */
546 void CoreSessionEventProcessor::processIrcEvent322(IrcEvent *e) {
547   if(!checkParamCount(e, 1))
548     return;
549
550   QString channelName;
551   quint32 userCount = 0;
552   QString topic;
553
554   switch(e->params().count()) {
555   case 3:
556     topic = e->params()[2];
557   case 2:
558     userCount = e->params()[1].toUInt();
559   case 1:
560     channelName = e->params()[0];
561   default:
562     break;
563   }
564   if(coreSession()->ircListHelper()->addChannel(e->networkId(), channelName, userCount, topic))
565     e->stop(); // consumed by IrcListHelper, so don't further process/show this event
566 }
567
568 /* RPL_LISTEND ":End of LIST" */
569 void CoreSessionEventProcessor::processIrcEvent323(IrcEvent *e) {
570   if(!checkParamCount(e, 1))
571     return;
572
573   if(coreSession()->ircListHelper()->endOfChannelList(e->networkId()))
574     e->stop(); // consumed by IrcListHelper, so don't further process/show this event
575 }
576
577 /* RPL_CHANNELMODEIS - "<channel> <mode> <mode params>" */
578 void CoreSessionEventProcessor::processIrcEvent324(IrcEvent *e) {
579   processIrcEventMode(e);
580 }
581
582 /* RPL_NOTOPIC */
583 void CoreSessionEventProcessor::processIrcEvent331(IrcEvent *e) {
584   if(!checkParamCount(e, 1))
585     return;
586
587   IrcChannel *chan = e->network()->ircChannel(e->params()[0]);
588   if(chan)
589     chan->setTopic(QString());
590 }
591
592 /* RPL_TOPIC */
593 void CoreSessionEventProcessor::processIrcEvent332(IrcEvent *e) {
594   if(!checkParamCount(e, 2))
595     return;
596
597   IrcChannel *chan = e->network()->ircChannel(e->params()[0]);
598   if(chan)
599     chan->setTopic(e->params()[1]);
600 }
601
602 /*  RPL_WHOREPLY: "<channel> <user> <host> <server> <nick>
603               ( "H" / "G" > ["*"] [ ( "@" / "+" ) ] :<hopcount> <real name>" */
604 void CoreSessionEventProcessor::processIrcEvent352(IrcEvent *e) {
605   if(!checkParamCount(e, 6))
606     return;
607
608   QString channel = e->params()[0];
609   IrcUser *ircuser = e->network()->ircUser(e->params()[4]);
610   if(ircuser) {
611     ircuser->setUser(e->params()[1]);
612     ircuser->setHost(e->params()[2]);
613
614     bool away = e->params()[5].startsWith("G");
615     ircuser->setAway(away);
616     ircuser->setServer(e->params()[3]);
617     ircuser->setRealName(e->params().last().section(" ", 1));
618   }
619
620   if(coreNetwork(e)->isAutoWhoInProgress(channel))
621     e->setFlag(EventManager::Silent);
622 }
623
624 /* RPL_NAMREPLY */
625 void CoreSessionEventProcessor::processIrcEvent353(IrcEvent *e) {
626   if(!checkParamCount(e, 3))
627     return;
628
629   // param[0] is either "=", "*" or "@" indicating a public, private or secret channel
630   // we don't use this information at the time beeing
631   QString channelname = e->params()[1];
632
633   IrcChannel *channel = e->network()->ircChannel(channelname);
634   if(!channel) {
635     qWarning() << Q_FUNC_INFO << "Received unknown target channel:" << channelname;
636     return;
637   }
638
639   QStringList nicks;
640   QStringList modes;
641
642   foreach(QString nick, e->params()[2].split(' ')) {
643     QString mode;
644
645     if(e->network()->prefixes().contains(nick[0])) {
646       mode = e->network()->prefixToMode(nick[0]);
647       nick = nick.mid(1);
648     }
649
650     nicks << nick;
651     modes << mode;
652   }
653
654   channel->joinIrcUsers(nicks, modes);
655 }
656
657 /* ERR_ERRONEUSNICKNAME */
658 void CoreSessionEventProcessor::processIrcEvent432(IrcEventNumeric *e) {
659   QString errnick;
660   if(e->params().count() < 2) {
661     // handle unreal-ircd bug, where unreal ircd doesnt supply a TARGET in ERR_ERRONEUSNICKNAME during registration phase:
662     // nick @@@
663     // :irc.scortum.moep.net 432  @@@ :Erroneous Nickname: Illegal characters
664     // correct server reply:
665     // :irc.scortum.moep.net 432 * @@@ :Erroneous Nickname: Illegal characters
666     e->params().prepend(e->target());
667     e->setTarget("*");
668   }
669   errnick = e->params()[0];
670
671   tryNextNick(e, errnick, true /* erroneus */);
672 }
673
674 /* ERR_NICKNAMEINUSE */
675 void CoreSessionEventProcessor::processIrcEvent433(IrcEventNumeric *e) {
676   if(!checkParamCount(e, 1))
677     return;
678
679   QString errnick = e->params().first();
680
681   // if there is a problem while connecting to the server -> we handle it
682   // but only if our connection has not been finished yet...
683   if(!e->network()->currentServer().isEmpty())
684     return;
685
686   tryNextNick(e, errnick);
687 }
688
689 /* ERR_UNAVAILRESOURCE */
690 void CoreSessionEventProcessor::processIrcEvent437(IrcEventNumeric *e) {
691   if(!checkParamCount(e, 1))
692     return;
693
694   QString errnick = e->params().first();
695
696   // if there is a problem while connecting to the server -> we handle it
697   // but only if our connection has not been finished yet...
698   if(!e->network()->currentServer().isEmpty())
699     return;
700
701   if(!e->network()->isChannelName(errnick))
702     tryNextNick(e, errnick);
703 }
704
705 /* template
706 void CoreSessionEventProcessor::processIrcEvent(IrcEvent *e) {
707   if(!checkParamCount(e, 1))
708     return;
709
710 }
711 */
712
713 /* Handle signals from Netsplit objects  */
714
715 void CoreSessionEventProcessor::handleNetsplitJoin(Network *net,
716                                                    const QString &channel,
717                                                    const QStringList &users,
718                                                    const QStringList &modes,
719                                                    const QString& quitMessage)
720 {
721   IrcChannel *ircChannel = net->ircChannel(channel);
722   if(!ircChannel) {
723     return;
724   }
725   QList<IrcUser *> ircUsers;
726   QStringList newModes = modes;
727   QStringList newUsers = users;
728
729   foreach(const QString &user, users) {
730     IrcUser *iu = net->ircUser(nickFromMask(user));
731     if(iu)
732       ircUsers.append(iu);
733     else { // the user already quit
734       int idx = users.indexOf(user);
735       newUsers.removeAt(idx);
736       newModes.removeAt(idx);
737     }
738   }
739
740   ircChannel->joinIrcUsers(ircUsers, newModes);
741   NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitJoin, net, channel, newUsers, quitMessage);
742   coreSession()->eventManager()->sendEvent(event);
743 }
744
745 void CoreSessionEventProcessor::handleNetsplitQuit(Network *net, const QString &channel, const QStringList &users, const QString& quitMessage) {
746   NetworkSplitEvent *event = new NetworkSplitEvent(EventManager::NetworkSplitQuit, net, channel, users, quitMessage);
747   coreSession()->eventManager()->sendEvent(event);
748   foreach(QString user, users) {
749     IrcUser *iu = net->ircUser(nickFromMask(user));
750     if(iu)
751       iu->quit();
752   }
753 }
754
755 void CoreSessionEventProcessor::handleEarlyNetsplitJoin(Network *net, const QString &channel, const QStringList &users, const QStringList &modes) {
756   IrcChannel *ircChannel = net->ircChannel(channel);
757   if(!ircChannel) {
758     qDebug() << "handleEarlyNetsplitJoin(): channel " << channel << " invalid";
759     return;
760   }
761   QList<NetworkEvent *> events;
762   QList<IrcUser *> ircUsers;
763   QStringList newModes = modes;
764
765   foreach(QString user, users) {
766     IrcUser *iu = net->updateNickFromMask(user);
767     if(iu) {
768       ircUsers.append(iu);
769       // fake event for scripts that consume join events
770       events << new IrcEvent(EventManager::IrcEventJoin, net, iu->hostmask(), QStringList() << channel);
771     }
772     else {
773       newModes.removeAt(users.indexOf(user));
774     }
775   }
776   ircChannel->joinIrcUsers(ircUsers, newModes);
777   foreach(NetworkEvent *event, events) {
778     event->setFlag(EventManager::Fake); // ignore this in here!
779     coreSession()->eventManager()->sendEvent(event);
780   }
781 }
782
783 void CoreSessionEventProcessor::handleNetsplitFinished() {
784   Netsplit* n = qobject_cast<Netsplit*>(sender());
785   Q_ASSERT(n);
786   QHash<QString, Netsplit *> splithash  = _netsplits.take(n->network());
787   splithash.remove(splithash.key(n));
788   if(splithash.count())
789     _netsplits[n->network()] = splithash;
790   n->deleteLater();
791 }
792
793 void CoreSessionEventProcessor::destroyNetsplits(NetworkId netId) {
794   Network *net = coreSession()->network(netId);
795   if(!net)
796     return;
797
798   QHash<QString, Netsplit *> splits = _netsplits.take(net);
799   qDeleteAll(splits);
800 }