fe9f2500e9a421c83f1216caa93c5c1dc6e62034
[quassel.git] / src / core / ircserverhandler.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-10 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 #include "ircserverhandler.h"
21
22 #include "util.h"
23
24 #include "coresession.h"
25 #include "coreirclisthelper.h"
26 #include "coreidentity.h"
27 #include "ctcphandler.h"
28
29 #include "ircuser.h"
30 #include "coreircchannel.h"
31 #include "logger.h"
32
33 #include <QDebug>
34
35 #ifdef HAVE_QCA2
36 #  include "cipher.h"
37 #endif
38
39 IrcServerHandler::IrcServerHandler(CoreNetwork *parent)
40   : CoreBasicHandler(parent),
41     _whois(false)
42 {
43   connect(parent, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetsplits()));
44 }
45
46 IrcServerHandler::~IrcServerHandler() {
47   destroyNetsplits();
48 }
49
50 /*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */
51 void IrcServerHandler::handleServerMsg(QByteArray msg) {
52   if(msg.isEmpty()) {
53     qWarning() << "Received empty string from server!";
54     return;
55   }
56
57   // Now we split the raw message into its various parts...
58   QString prefix = "";
59   QByteArray trailing;
60   QString cmd;
61
62   // First, check for a trailing parameter introduced by " :", since this might screw up splitting the msg
63   // NOTE: This assumes that this is true in raw encoding, but well, hopefully there are no servers running in japanese on protocol level...
64   int idx = msg.indexOf(" :");
65   if(idx >= 0) {
66     if(msg.length() > idx + 2)
67       trailing = msg.mid(idx + 2);
68     msg = msg.left(idx);
69   }
70   // OK, now it is safe to split...
71   QList<QByteArray> params = msg.split(' ');
72
73   // This could still contain empty elements due to (faulty?) ircds sending multiple spaces in a row
74   // Also, QByteArray is not nearly as convenient to work with as QString for such things :)
75   QList<QByteArray>::iterator iter = params.begin();
76   while(iter != params.end()) {
77     if(iter->isEmpty())
78       iter = params.erase(iter);
79     else
80       ++iter;
81   }
82
83   if(!trailing.isEmpty()) params << trailing;
84   if(params.count() < 1) {
85     qWarning() << "Received invalid string from server!";
86     return;
87   }
88
89   QString foo = serverDecode(params.takeFirst());
90
91   // with SASL, the command is 'AUTHENTICATE +' and we should check for this here.
92   if(foo == QString("AUTHENTICATE +")) {
93     handleAuthenticate();
94     return;
95   }
96
97   // a colon as the first chars indicates the existence of a prefix
98   if(foo[0] == ':') {
99     foo.remove(0, 1);
100     prefix = foo;
101     if(params.count() < 1) {
102       qWarning() << "Received invalid string from server!";
103       return;
104     }
105     foo = serverDecode(params.takeFirst());
106   }
107
108   // next string without a whitespace is the command
109   cmd = foo.trimmed().toUpper();
110
111   // numeric replies have the target as first param (RFC 2812 - 2.4). this is usually our own nick. Remove this!
112   uint num = cmd.toUInt();
113   if(num > 0) {
114     if(params.count() == 0) {
115       qWarning() << "Message received from server violates RFC and is ignored!" << msg;
116       return;
117     }
118     _target = serverDecode(params.takeFirst());
119   } else {
120     _target = QString();
121   }
122
123   // note that the IRC server is still alive
124   network()->resetPingTimeout();
125
126   // Now we try to find a handler for this message. BTW, I do love the Trolltech guys ;-)
127   handle(cmd, Q_ARG(QString, prefix), Q_ARG(QList<QByteArray>, params));
128 }
129
130
131 void IrcServerHandler::defaultHandler(QString cmd, const QString &prefix, const QList<QByteArray> &rawparams) {
132   // many commands are handled by the event system now
133   Q_UNUSED(cmd)
134   Q_UNUSED(prefix)
135   Q_UNUSED(rawparams)
136 }
137
138 //******************************/
139 // IRC SERVER HANDLER
140 //******************************/
141
142 void IrcServerHandler::handleJoin(const QString &prefix, const QList<QByteArray> &params) {
143   if(!checkParamCount("IrcServerHandler::handleJoin()", params, 1))
144     return;
145
146   QString channel = serverDecode(params[0]);
147   IrcUser *ircuser = network()->updateNickFromMask(prefix);
148
149   bool handledByNetsplit = false;
150   if(!_netsplits.empty()) {
151     foreach(Netsplit* n, _netsplits) {
152       handledByNetsplit = n->userJoined(prefix, channel);
153       if(handledByNetsplit)
154         break;
155     }
156   }
157
158   // normal join
159   if(!handledByNetsplit) {
160     emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, prefix);
161     ircuser->joinChannel(channel);
162   }
163   //qDebug() << "IrcServerHandler::handleJoin()" << prefix << params;
164
165   if(network()->isMe(ircuser)) {
166     network()->setChannelJoined(channel);
167     putCmd("MODE", params[0]); // we want to know the modes of the channel we just joined, so we ask politely
168   }
169 }
170
171 void IrcServerHandler::handleMode(const QString &prefix, const QList<QByteArray> &params) {
172   if(!checkParamCount("IrcServerHandler::handleMode()", params, 2))
173     return;
174
175   if(network()->isChannelName(serverDecode(params[0]))) {
176     // Channel Modes
177     emit displayMsg(Message::Mode, BufferInfo::ChannelBuffer, serverDecode(params[0]), serverDecode(params).join(" "), prefix);
178
179     IrcChannel *channel = network()->ircChannel(params[0]);
180     if(!channel) {
181       // we received mode information for a channel we're not in. that means probably we've just been kicked out or something like that
182       // anyways: we don't have a place to store the data --> discard the info.
183       return;
184     }
185
186     QString modes = params[1];
187     bool add = true;
188     int paramOffset = 2;
189     for(int c = 0; c < modes.length(); c++) {
190       if(modes[c] == '+') {
191         add = true;
192         continue;
193       }
194       if(modes[c] == '-') {
195         add = false;
196         continue;
197       }
198
199       if(network()->prefixModes().contains(modes[c])) {
200         // user channel modes (op, voice, etc...)
201         if(paramOffset < params.count()) {
202           IrcUser *ircUser = network()->ircUser(params[paramOffset]);
203           if(!ircUser) {
204             qWarning() << Q_FUNC_INFO << "Unknown IrcUser:" << params[paramOffset];
205           } else {
206             if(add) {
207               bool handledByNetsplit = false;
208               if(!_netsplits.empty()) {
209                 foreach(Netsplit* n, _netsplits) {
210                   handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name());
211                   if(handledByNetsplit) {
212                     n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c]));
213                     break;
214                   }
215                 }
216               }
217               if(!handledByNetsplit)
218                 channel->addUserMode(ircUser, QString(modes[c]));
219             }
220             else
221               channel->removeUserMode(ircUser, QString(modes[c]));
222           }
223         } else {
224           qWarning() << "Received MODE with too few parameters:" << serverDecode(params);
225         }
226         paramOffset++;
227       } else {
228         // regular channel modes
229         QString value;
230         Network::ChannelModeType modeType = network()->channelModeType(modes[c]);
231         if(modeType == Network::A_CHANMODE || modeType == Network::B_CHANMODE || (modeType == Network::C_CHANMODE && add)) {
232           if(paramOffset < params.count()) {
233             value = params[paramOffset];
234           } else {
235             qWarning() << "Received MODE with too few parameters:" << serverDecode(params);
236           }
237           paramOffset++;
238         }
239
240         if(add)
241           channel->addChannelMode(modes[c], value);
242         else
243           channel->removeChannelMode(modes[c], value);
244       }
245     }
246
247   } else {
248     // pure User Modes
249     IrcUser *ircUser = network()->newIrcUser(params[0]);
250     QString modeString(serverDecode(params[1]));
251     QString addModes;
252     QString removeModes;
253     bool add = false;
254     for(int c = 0; c < modeString.count(); c++) {
255       if(modeString[c] == '+') {
256         add = true;
257         continue;
258       }
259       if(modeString[c] == '-') {
260         add = false;
261         continue;
262       }
263       if(add)
264         addModes += modeString[c];
265       else
266         removeModes += modeString[c];
267     }
268     if(!addModes.isEmpty())
269       ircUser->addUserModes(addModes);
270     if(!removeModes.isEmpty())
271       ircUser->removeUserModes(removeModes);
272
273     if(network()->isMe(ircUser)) {
274       network()->updatePersistentModes(addModes, removeModes);
275     }
276
277     // FIXME: redirect
278     emit displayMsg(Message::Mode, BufferInfo::StatusBuffer, "", serverDecode(params).join(" "), prefix);
279   }
280 }
281
282 void IrcServerHandler::handleNotice(const QString &prefix, const QList<QByteArray> &params) {
283   if(!checkParamCount("IrcServerHandler::handleNotice()", params, 2))
284     return;
285
286
287   QStringList targets = serverDecode(params[0]).split(',', QString::SkipEmptyParts);
288   QStringList::const_iterator targetIter;
289   for(targetIter = targets.constBegin(); targetIter != targets.constEnd(); targetIter++) {
290     QString target = *targetIter;
291
292     // special treatment for welcome messages like:
293     // :ChanServ!ChanServ@services. NOTICE egst :[#apache] Welcome, this is #apache. Please read the in-channel topic message. This channel is being logged by IRSeekBot. If you have any question please see http://blog.freenode.net/?p=68
294     if(!network()->isChannelName(target)) {
295       QString msg = serverDecode(params[1]);
296       QRegExp welcomeRegExp("^\\[([^\\]]+)\\] ");
297       if(welcomeRegExp.indexIn(msg) != -1) {
298         QString channelname = welcomeRegExp.cap(1);
299         msg = msg.mid(welcomeRegExp.matchedLength());
300         CoreIrcChannel *chan = static_cast<CoreIrcChannel *>(network()->ircChannel(channelname)); // we only have CoreIrcChannels in the core, so this cast is safe
301         if(chan && !chan->receivedWelcomeMsg()) {
302           chan->setReceivedWelcomeMsg();
303           emit displayMsg(Message::Notice, BufferInfo::ChannelBuffer, channelname, msg, prefix);
304           continue;
305         }
306       }
307     }
308
309     if(prefix.isEmpty() || target == "AUTH") {
310       target = "";
311     } else {
312       if(!target.isEmpty() && network()->prefixes().contains(target[0]))
313         target = target.mid(1);
314       if(!network()->isChannelName(target))
315         target = nickFromMask(prefix);
316     }
317
318     network()->ctcpHandler()->parse(Message::Notice, prefix, target, params[1]);
319   }
320
321 }
322
323 void IrcServerHandler::handlePing(const QString &prefix, const QList<QByteArray> &params) {
324   Q_UNUSED(prefix);
325   putCmd("PONG", params);
326 }
327
328 void IrcServerHandler::handlePong(const QString &prefix, const QList<QByteArray> &params) {
329   Q_UNUSED(prefix);
330   // the server is supposed to send back what we passed as param. and we send a timestamp
331   // but using quote and whatnought one can send arbitrary pings, so we have to do some sanity checks
332   if(params.count() < 2)
333     return;
334
335   QString timestamp = serverDecode(params[1]);
336   QTime sendTime = QTime::fromString(timestamp, "hh:mm:ss.zzz");
337   if(!sendTime.isValid()) {
338     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", "PONG " + serverDecode(params).join(" "), prefix);
339     return;
340   }
341
342   network()->setLatency(sendTime.msecsTo(QTime::currentTime()) / 2);
343 }
344
345 void IrcServerHandler::handlePrivmsg(const QString &prefix, const QList<QByteArray> &params) {
346   if(!checkParamCount("IrcServerHandler::handlePrivmsg()", params, 1))
347     return;
348
349   IrcUser *ircuser = network()->updateNickFromMask(prefix);
350   if(!ircuser) {
351     qWarning() << "IrcServerHandler::handlePrivmsg(): Unknown IrcUser!";
352     return;
353   }
354
355   if(params.isEmpty()) {
356     qWarning() << "IrcServerHandler::handlePrivmsg(): received PRIVMSG without target or message from:" << prefix;
357     return;
358   }
359
360   QString senderNick = nickFromMask(prefix);
361
362   QByteArray msg = params.count() < 2
363     ? QByteArray("")
364     : params[1];
365
366   QStringList targets = serverDecode(params[0]).split(',', QString::SkipEmptyParts);
367   QStringList::const_iterator targetIter;
368   for(targetIter = targets.constBegin(); targetIter != targets.constEnd(); targetIter++) {
369     const QString &target = network()->isChannelName(*targetIter)
370       ? *targetIter
371       : senderNick;
372
373 #ifdef HAVE_QCA2
374     msg = decrypt(target, msg);
375 #endif
376     // it's possible to pack multiple privmsgs into one param using ctcp
377     // - > we let the ctcpHandler do the work
378     network()->ctcpHandler()->parse(Message::Plain, prefix, target, msg);
379   }
380 }
381
382 void IrcServerHandler::handleQuit(const QString &prefix, const QList<QByteArray> &params) {
383   IrcUser *ircuser = network()->updateNickFromMask(prefix);
384   if(!ircuser) return;
385
386   QString msg;
387   if(params.count() > 0)
388     msg = userDecode(ircuser->nick(), params[0]);
389
390   // check if netsplit
391   if(Netsplit::isNetsplit(msg)) {
392     Netsplit *n;
393     if(!_netsplits.contains(msg)) {
394       n = new Netsplit();
395       connect(n, SIGNAL(finished()), this, SLOT(handleNetsplitFinished()));
396       connect(n, SIGNAL(netsplitJoin(const QString&, const QStringList&, const QStringList&, const QString&)),
397               this, SLOT(handleNetsplitJoin(const QString&, const QStringList&, const QStringList&, const QString&)));
398       connect(n, SIGNAL(netsplitQuit(const QString&, const QStringList&, const QString&)),
399               this, SLOT(handleNetsplitQuit(const QString&, const QStringList&, const QString&)));
400       connect(n, SIGNAL(earlyJoin(const QString&, const QStringList&, const QStringList&)),
401               this, SLOT(handleEarlyNetsplitJoin(const QString&, const QStringList&, const QStringList&)));
402       _netsplits.insert(msg, n);
403     }
404     else {
405       n = _netsplits[msg];
406     }
407     // add this user to the netsplit
408     n->userQuit(prefix, ircuser->channels(),msg);
409   }
410   // normal quit
411   else {
412     foreach(QString channel, ircuser->channels())
413       emit displayMsg(Message::Quit, BufferInfo::ChannelBuffer, channel, msg, prefix);
414     ircuser->quit();
415   }
416 }
417
418 void IrcServerHandler::handleTopic(const QString &prefix, const QList<QByteArray> &params) {
419   if(!checkParamCount("IrcServerHandler::handleTopic()", params, 1))
420     return;
421
422   IrcUser *ircuser = network()->updateNickFromMask(prefix);
423   if(!ircuser)
424     return;
425
426   IrcChannel *channel = network()->ircChannel(serverDecode(params[0]));
427   if(!channel)
428     return;
429
430   QString topic;
431   if(params.count() > 1) {
432     QByteArray rawTopic = params[1];
433 #ifdef HAVE_QCA2
434     rawTopic = decrypt(channel->name(), rawTopic, true);
435 #endif
436     topic = channelDecode(channel->name(), rawTopic);
437   }
438
439   channel->setTopic(topic);
440
441   emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel->name(), tr("%1 has changed topic for %2 to: \"%3\"").arg(ircuser->nick()).arg(channel->name()).arg(topic));
442 }
443
444 void IrcServerHandler::handleCap(const QString &prefix, const QList<QByteArray> &params) {
445     // for SASL, there will only be a single param of 'sasl', however you can check here for
446     // additional CAP messages (ls, multi-prefix, et cetera).
447
448     Q_UNUSED(prefix);
449
450     if(params.size() == 3) {
451         QString param = serverDecode(params[2]);
452         if(param == QString("sasl")) {  // SASL Ready
453             network()->putRawLine(serverEncode("AUTHENTICATE PLAIN"));  // Only working with PLAIN atm, blowfish later
454         }
455     }
456 }
457
458 void IrcServerHandler::handleAuthenticate() {
459     QString construct = network()->saslAccount();
460     construct.append(QChar(QChar::Null));
461     construct.append(network()->saslAccount());
462     construct.append(QChar(QChar::Null));
463     construct.append(network()->saslPassword());
464     QByteArray saslData = QByteArray(construct.toAscii().toBase64());
465     saslData.prepend(QString("AUTHENTICATE ").toAscii());
466     network()->putRawLine(saslData);
467 }
468
469 /* RPL_WELCOME */
470 void IrcServerHandler::handle001(const QString &prefix, const QList<QByteArray> &params) {
471   network()->setCurrentServer(prefix);
472
473   if(params.isEmpty()) {
474     emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", QString("%1 didn't supply a valid welcome message... expect some serious issues..."));
475   }
476   // there should be only one param: "Welcome to the Internet Relay Network <nick>!<user>@<host>"
477   QString param = serverDecode(params[0]);
478   QString myhostmask = param.section(' ', -1, -1);
479
480   network()->setMyNick(nickFromMask(myhostmask));
481
482   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", param, prefix);
483 }
484
485 /* RPL_ISUPPORT */
486 // TODO Complete 005 handling, also use sensible defaults for non-sent stuff
487 void IrcServerHandler::handle005(const QString &prefix, const QList<QByteArray> &params) {
488   Q_UNUSED(prefix);
489   const int numParams = params.size();
490   if(numParams == 0) {
491     emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Received RPL_ISUPPORT (005) without parameters!"), prefix);
492     return;
493   }
494
495   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", serverDecode(params).join(" "), prefix);
496
497   QString rpl_isupport_suffix = serverDecode(params.last());
498   if(!rpl_isupport_suffix.toLower().contains("are supported by this server")) {
499     emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Received non RFC compliant RPL_ISUPPORT: this can lead to unexpected behavior!"), prefix);
500   }
501
502   QString rawSupport;
503   QString key, value;
504   for(int i = 0; i < numParams - 1; i++) {
505     QString rawSupport = serverDecode(params[i]);
506     QString key = rawSupport.section("=", 0, 0);
507     QString value = rawSupport.section("=", 1);
508     network()->addSupport(key, value);
509   }
510
511   /* determine our prefixes here to get an accurate result */
512   network()->determinePrefixes();
513 }
514
515 /* RPL_UMODEIS - "<user_modes> [<user_mode_params>]" */
516 void IrcServerHandler::handle221(const QString &prefix, const QList<QByteArray> &params) {
517   Q_UNUSED(prefix)
518   //TODO: save information in network object
519   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("%1").arg(serverDecode(params).join(" ")));
520 }
521
522 /* RPL_STATSCONN - "Highest connection cout: 8000 (7999 clients)" */
523 void IrcServerHandler::handle250(const QString &prefix, const QList<QByteArray> &params) {
524   Q_UNUSED(prefix)
525   //TODO: save information in network object
526   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("%1").arg(serverDecode(params).join(" ")));
527 }
528
529 /* RPL_LOCALUSERS - "Current local user: 5024  Max: 7999 */
530 void IrcServerHandler::handle265(const QString &prefix, const QList<QByteArray> &params) {
531   Q_UNUSED(prefix)
532   //TODO: save information in network object
533   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("%1").arg(serverDecode(params).join(" ")));
534 }
535
536 /* RPL_GLOBALUSERS - "Current global users: 46093  Max: 47650" */
537 void IrcServerHandler::handle266(const QString &prefix, const QList<QByteArray> &params) {
538   Q_UNUSED(prefix)
539   //TODO: save information in network object
540   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("%1").arg(serverDecode(params).join(" ")));
541 }
542
543 /*
544 WHOIS-Message:
545    Replies 311 - 313, 317 - 319 are all replies generated in response to a WHOIS message.
546   and 301 (RPL_AWAY)
547               "<nick> :<away message>"
548 WHO-Message:
549    Replies 352 and 315 paired are used to answer a WHO message.
550
551 WHOWAS-Message:
552    Replies 314 and 369 are responses to a WHOWAS message.
553
554 */
555
556
557 /*   RPL_AWAY - "<nick> :<away message>" */
558 void IrcServerHandler::handle301(const QString &prefix, const QList<QByteArray> &params) {
559   Q_UNUSED(prefix);
560   if(!checkParamCount("IrcServerHandler::handle301()", params, 2))
561     return;
562
563
564   QString nickName = serverDecode(params[0]);
565   QString awayMessage = userDecode(nickName, params[1]);
566
567   IrcUser *ircuser = network()->ircUser(nickName);
568   if(ircuser) {
569     ircuser->setAwayMessage(awayMessage);
570     ircuser->setAway(true);
571   }
572
573   // FIXME: proper redirection needed
574   if(_whois) {
575     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is away: \"%2\"").arg(nickName).arg(awayMessage));
576   } else {
577     if(ircuser) {
578       int now = QDateTime::currentDateTime().toTime_t();
579       int silenceTime = 60;
580       if(ircuser->lastAwayMessage() + silenceTime < now) {
581         emit displayMsg(Message::Server, BufferInfo::QueryBuffer, params[0], tr("%1 is away: \"%2\"").arg(nickName).arg(awayMessage));
582       }
583       ircuser->setLastAwayMessage(now);
584     } else {
585       // probably should not happen
586       emit displayMsg(Message::Server, BufferInfo::QueryBuffer, params[0], tr("%1 is away: \"%2\"").arg(nickName).arg(awayMessage));
587     }
588   }
589 }
590
591 // 305  RPL_UNAWAY
592 //      ":You are no longer marked as being away"
593 void IrcServerHandler::handle305(const QString &prefix, const QList<QByteArray> &params) {
594   Q_UNUSED(prefix);
595   IrcUser *me = network()->me();
596   if(me)
597     me->setAway(false);
598
599   if(!network()->autoAwayActive()) {
600     if(!params.isEmpty())
601       emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", serverDecode(params[0]));
602   } else {
603     network()->setAutoAwayActive(false);
604   }
605 }
606
607 // 306  RPL_NOWAWAY
608 //      ":You have been marked as being away"
609 void IrcServerHandler::handle306(const QString &prefix, const QList<QByteArray> &params) {
610   Q_UNUSED(prefix);
611   IrcUser *me = network()->me();
612   if(me)
613     me->setAway(true);
614
615   if(!params.isEmpty() && !network()->autoAwayActive())
616     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", serverDecode(params[0]));
617 }
618
619 /* RPL_WHOISSERVICE - "<user> is registered nick" */
620 void IrcServerHandler::handle307(const QString &prefix, const QList<QByteArray> &params) {
621   Q_UNUSED(prefix)
622   if(!checkParamCount("IrcServerHandler::handle307()", params, 1))
623     return;
624
625   QString whoisServiceReply = serverDecode(params).join(" ");
626   IrcUser *ircuser = network()->ircUser(serverDecode(params[0]));
627   if(ircuser) {
628     ircuser->setWhoisServiceReply(whoisServiceReply);
629   }
630   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1").arg(whoisServiceReply));
631 }
632
633 /* RPL_SUSERHOST - "<user> is available for help." */
634 void IrcServerHandler::handle310(const QString &prefix, const QList<QByteArray> &params) {
635   Q_UNUSED(prefix)
636   if(!checkParamCount("IrcServerHandler::handle310()", params, 1))
637     return;
638
639   QString suserHost = serverDecode(params).join(" ");
640   IrcUser *ircuser = network()->ircUser(serverDecode(params[0]));
641   if(ircuser) {
642     ircuser->setSuserHost(suserHost);
643   }
644   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1").arg(suserHost));
645 }
646
647 /*  RPL_WHOISUSER - "<nick> <user> <host> * :<real name>" */
648 void IrcServerHandler::handle311(const QString &prefix, const QList<QByteArray> &params) {
649   Q_UNUSED(prefix)
650   if(!checkParamCount("IrcServerHandler::handle311()", params, 3))
651     return;
652
653   _whois = true;
654   IrcUser *ircuser = network()->ircUser(serverDecode(params[0]));
655   if(ircuser) {
656     ircuser->setUser(serverDecode(params[1]));
657     ircuser->setHost(serverDecode(params[2]));
658     ircuser->setRealName(serverDecode(params.last()));
659     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is %2 (%3)") .arg(ircuser->nick()).arg(ircuser->hostmask()).arg(ircuser->realName()));
660   } else {
661     QString host = QString("%1!%2@%3").arg(serverDecode(params[0])).arg(serverDecode(params[1])).arg(serverDecode(params[2]));
662     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is %2 (%3)") .arg(serverDecode(params[0])).arg(host).arg(serverDecode(params.last())));
663   }
664 }
665
666 /*  RPL_WHOISSERVER -  "<nick> <server> :<server info>" */
667 void IrcServerHandler::handle312(const QString &prefix, const QList<QByteArray> &params) {
668   Q_UNUSED(prefix)
669   if(!checkParamCount("IrcServerHandler::handle312()", params, 2))
670     return;
671
672   IrcUser *ircuser = network()->ircUser(serverDecode(params[0]));
673   if(ircuser) {
674     ircuser->setServer(serverDecode(params[1]));
675   }
676
677   QString returnString = tr("%1 is online via %2 (%3)").arg(serverDecode(params[0])).arg(serverDecode(params[1])).arg(serverDecode(params.last()));
678   if(_whois) {
679     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1").arg(returnString));
680   } else {
681     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whowas] %1").arg(returnString));
682   }
683 }
684
685 /*  RPL_WHOISOPERATOR - "<nick> :is an IRC operator" */
686 void IrcServerHandler::handle313(const QString &prefix, const QList<QByteArray> &params) {
687   Q_UNUSED(prefix)
688   if(!checkParamCount("IrcServerHandler::handle313()", params, 1))
689     return;
690
691   IrcUser *ircuser = network()->ircUser(serverDecode(params[0]));
692   if(ircuser) {
693     ircuser->setIrcOperator(params.last());
694   }
695   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1").arg(serverDecode(params).join(" ")));
696 }
697
698 /*  RPL_WHOWASUSER - "<nick> <user> <host> * :<real name>" */
699 void IrcServerHandler::handle314(const QString &prefix, const QList<QByteArray> &params) {
700   Q_UNUSED(prefix)
701   if(!checkParamCount("IrcServerHandler::handle314()", params, 3))
702     return;
703
704   QString nick = serverDecode(params[0]);
705   QString hostmask = QString("%1@%2").arg(serverDecode(params[1])).arg(serverDecode(params[2]));
706   QString realName = serverDecode(params.last());
707   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whowas] %1 was %2 (%3)").arg(nick).arg(hostmask).arg(realName));
708 }
709
710 /*  RPL_ENDOFWHO: "<name> :End of WHO list" */
711 void IrcServerHandler::handle315(const QString &prefix, const QList<QByteArray> &params) {
712   Q_UNUSED(prefix);
713   if(!checkParamCount("IrcServerHandler::handle315()", params, 1))
714     return;
715
716   QStringList p = serverDecode(params);
717   if(network()->setAutoWhoDone(p[0])) {
718     return; // stay silent
719   }
720   p.takeLast(); // should be "End of WHO list"
721   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] End of /WHO list for %1").arg(p.join(" ")));
722 }
723
724 /*  RPL_WHOISIDLE - "<nick> <integer> :seconds idle"
725    (real life: "<nick> <integer> <integer> :seconds idle, signon time) */
726 void IrcServerHandler::handle317(const QString &prefix, const QList<QByteArray> &params) {
727   Q_UNUSED(prefix);
728   if(!checkParamCount("IrcServerHandler::handle317()", params, 2))
729     return;
730
731   QString nick = serverDecode(params[0]);
732   IrcUser *ircuser = network()->ircUser(nick);
733
734   QDateTime now = QDateTime::currentDateTime();
735   int idleSecs = serverDecode(params[1]).toInt();
736   idleSecs *= -1;
737
738   if(ircuser) {
739     ircuser->setIdleTime(now.addSecs(idleSecs));
740     if(params.size() > 3) { // if we have more then 3 params we have the above mentioned "real life" situation
741       int loginTime = serverDecode(params[2]).toInt();
742       ircuser->setLoginTime(QDateTime::fromTime_t(loginTime));
743       emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is logged in since %2").arg(ircuser->nick()).arg(ircuser->loginTime().toString()));
744     }
745     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is idling for %2 (%3)").arg(ircuser->nick()).arg(secondsToString(ircuser->idleTime().secsTo(now))).arg(ircuser->idleTime().toString()));
746   } else {
747     QDateTime idleSince = now.addSecs(idleSecs);
748     if (params.size() > 3) { // we have a signon time
749       int loginTime = serverDecode(params[2]).toInt();
750       QDateTime datetime = QDateTime::fromTime_t(loginTime);
751       emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is logged in since %2").arg(nick).arg(datetime.toString()));
752     }
753     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is idling for %2 (%3)").arg(nick).arg(secondsToString(idleSince.secsTo(now))).arg(idleSince.toString()));
754   }
755 }
756
757 /*  RPL_ENDOFWHOIS - "<nick> :End of WHOIS list" */
758 void IrcServerHandler::handle318(const QString &prefix, const QList<QByteArray> &params) {
759   Q_UNUSED(prefix)
760   _whois = false;
761   QStringList parameter = serverDecode(params);
762   parameter.removeFirst();
763   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1").arg(parameter.join(" ")));
764 }
765
766 /*  RPL_WHOISCHANNELS - "<nick> :*( ( "@" / "+" ) <channel> " " )" */
767 void IrcServerHandler::handle319(const QString &prefix, const QList<QByteArray> &params) {
768   Q_UNUSED(prefix)
769   if(!checkParamCount("IrcServerHandler::handle319()", params, 2))
770     return;
771
772   QString nick = serverDecode(params.first());
773   QStringList op;
774   QStringList voice;
775   QStringList user;
776   foreach (QString channel, serverDecode(params.last()).split(" ")) {
777     if(channel.startsWith("@"))
778        op.append(channel.remove(0,1));
779     else if(channel.startsWith("+"))
780       voice.append(channel.remove(0,1));
781     else
782       user.append(channel);
783   }
784   if(!user.isEmpty())
785     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is a user on channels: %2").arg(nick).arg(user.join(" ")));
786   if(!voice.isEmpty())
787     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 has voice on channels: %2").arg(nick).arg(voice.join(" ")));
788   if(!op.isEmpty())
789     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is an operator on channels: %2").arg(nick).arg(op.join(" ")));
790 }
791
792 /*  RPL_WHOISVIRT - "<nick> is identified to services" */
793 void IrcServerHandler::handle320(const QString &prefix, const QList<QByteArray> &params) {
794   Q_UNUSED(prefix);
795   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1").arg(serverDecode(params).join(" ")));
796 }
797
798 /* RPL_LIST -  "<channel> <# visible> :<topic>" */
799 void IrcServerHandler::handle322(const QString &prefix, const QList<QByteArray> &params) {
800   Q_UNUSED(prefix)
801   QString channelName;
802   quint32 userCount = 0;
803   QString topic;
804
805   int paramCount = params.count();
806   switch(paramCount) {
807   case 3:
808     topic = serverDecode(params[2]);
809   case 2:
810     userCount = serverDecode(params[1]).toUInt();
811   case 1:
812     channelName = serverDecode(params[0]);
813   default:
814     break;
815   }
816   if(!coreSession()->ircListHelper()->addChannel(network()->networkId(), channelName, userCount, topic))
817     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Channel %1 has %2 users. Topic is: %3").arg(channelName).arg(userCount).arg(topic));
818 }
819
820 /* RPL_LISTEND ":End of LIST" */
821 void IrcServerHandler::handle323(const QString &prefix, const QList<QByteArray> &params) {
822   Q_UNUSED(prefix)
823   Q_UNUSED(params)
824
825   if(!coreSession()->ircListHelper()->endOfChannelList(network()->networkId()))
826     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("End of channel list"));
827 }
828
829 /* RPL_CHANNELMODEIS - "<channel> <mode> <mode params>" */
830 void IrcServerHandler::handle324(const QString &prefix, const QList<QByteArray> &params) {
831   Q_UNUSED(prefix);
832   handleMode(prefix, params);
833 }
834
835 /* RPL_??? - "<channel> <homepage> */
836 void IrcServerHandler::handle328(const QString &prefix, const QList<QByteArray> &params) {
837   Q_UNUSED(prefix);
838   if(!checkParamCount("IrcServerHandler::handle328()", params, 2))
839     return;
840
841   QString channel = serverDecode(params[0]);
842   QString homepage = serverDecode(params[1]);
843
844   emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, tr("Homepage for %1 is %2").arg(channel, homepage));
845 }
846
847
848 /* RPL_??? - "<channel> <creation time (unix)>" */
849 void IrcServerHandler::handle329(const QString &prefix, const QList<QByteArray> &params) {
850   Q_UNUSED(prefix);
851   if(!checkParamCount("IrcServerHandler::handle329()", params, 2))
852     return;
853
854   QString channel = serverDecode(params[0]);
855   uint unixtime = params[1].toUInt();
856   if(!unixtime) {
857     qWarning() << Q_FUNC_INFO << "received invalid timestamp:" << params[1];
858     return;
859   }
860   QDateTime time = QDateTime::fromTime_t(unixtime);
861
862   emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, tr("Channel %1 created on %2").arg(channel, time.toString()));
863 }
864
865 /*  RPL_WHOISACCOUNT: "<nick> <account> :is authed as */
866 void IrcServerHandler::handle330(const QString &prefix, const QList<QByteArray> &params) {
867   Q_UNUSED(prefix);
868   if(!checkParamCount("IrcServerHandler::handle330()", params, 3))
869     return;
870
871   QString nick = serverDecode(params[0]);
872   QString account = serverDecode(params[1]);
873
874   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "",  tr("[Whois] %1 is authed as %2").arg(nick).arg(account));
875 }
876
877 /* RPL_NOTOPIC */
878 void IrcServerHandler::handle331(const QString &prefix, const QList<QByteArray> &params) {
879   Q_UNUSED(prefix);
880   if(!checkParamCount("IrcServerHandler::handle331()", params, 1))
881     return;
882
883   QString channel = serverDecode(params[0]);
884   IrcChannel *chan = network()->ircChannel(channel);
885   if(chan)
886     chan->setTopic(QString());
887
888   emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel, tr("No topic is set for %1.").arg(channel));
889 }
890
891 /* RPL_TOPIC */
892 void IrcServerHandler::handle332(const QString &prefix, const QList<QByteArray> &params) {
893   Q_UNUSED(prefix);
894   if(!checkParamCount("IrcServerHandler::handle332()", params, 2))
895     return;
896
897   QString channel = serverDecode(params[0]);
898   QByteArray rawTopic = params[1];
899 #ifdef HAVE_QCA2
900   rawTopic = decrypt(channel, rawTopic, true);
901 #endif
902   QString topic = channelDecode(channel, rawTopic);
903
904   IrcChannel *chan = network()->ircChannel(channel);
905   if(chan)
906     chan->setTopic(topic);
907
908   emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel, tr("Topic for %1 is \"%2\"").arg(channel, topic));
909 }
910
911 /* Topic set by... */
912 void IrcServerHandler::handle333(const QString &prefix, const QList<QByteArray> &params) {
913   Q_UNUSED(prefix);
914   if(!checkParamCount("IrcServerHandler::handle333()", params, 3))
915     return;
916
917   QString channel = serverDecode(params[0]);
918   emit displayMsg(Message::Topic, BufferInfo::ChannelBuffer, channel,
919                   tr("Topic set by %1 on %2") .arg(serverDecode(params[1]), QDateTime::fromTime_t(channelDecode(channel, params[2]).toUInt()).toString()));
920 }
921
922 /* RPL_INVITING - "<nick> <channel>*/
923 void IrcServerHandler::handle341(const QString &prefix, const QList<QByteArray> &params) {
924   Q_UNUSED(prefix);
925   if(!checkParamCount("IrcServerHandler::handle341()", params, 2))
926     return;
927
928   QString nick = serverDecode(params[0]);
929
930   IrcChannel *channel = network()->ircChannel(serverDecode(params[1]));
931   if(!channel) {
932     qWarning() << "IrcServerHandler::handle341(): unknown channel:" << params[1];
933     return;
934   }
935
936   emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel->name(), tr("%1 has been invited to %2").arg(nick).arg(channel->name()));
937 }
938
939 /*  RPL_WHOREPLY: "<channel> <user> <host> <server> <nick>
940               ( "H" / "G" > ["*"] [ ( "@" / "+" ) ] :<hopcount> <real name>" */
941 void IrcServerHandler::handle352(const QString &prefix, const QList<QByteArray> &params) {
942   Q_UNUSED(prefix)
943   if(!checkParamCount("IrcServerHandler::handle352()", params, 6))
944     return;
945
946   QString channel = serverDecode(params[0]);
947   IrcUser *ircuser = network()->ircUser(serverDecode(params[4]));
948   if(ircuser) {
949     ircuser->setUser(serverDecode(params[1]));
950     ircuser->setHost(serverDecode(params[2]));
951
952     bool away = serverDecode(params[5]).startsWith("G") ? true : false;
953     ircuser->setAway(away);
954     ircuser->setServer(serverDecode(params[3]));
955     ircuser->setRealName(serverDecode(params.last()).section(" ", 1));
956   }
957
958   if(!network()->isAutoWhoInProgress(channel)) {
959     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Who] %1").arg(serverDecode(params).join(" ")));
960   }
961 }
962
963 /* RPL_NAMREPLY */
964 void IrcServerHandler::handle353(const QString &prefix, const QList<QByteArray> &params) {
965   Q_UNUSED(prefix);
966   if(!checkParamCount("IrcServerHandler::handle353()", params, 3))
967     return;
968
969   // param[0] is either "=", "*" or "@" indicating a public, private or secret channel
970   // we don't use this information at the time beeing
971   QString channelname = serverDecode(params[1]);
972
973   IrcChannel *channel = network()->ircChannel(channelname);
974   if(!channel) {
975     qWarning() << "IrcServerHandler::handle353(): received unknown target channel:" << channelname;
976     return;
977   }
978
979   QStringList nicks;
980   QStringList modes;
981
982   foreach(QString nick, serverDecode(params[2]).split(' ')) {
983     QString mode = QString();
984
985     if(network()->prefixes().contains(nick[0])) {
986       mode = network()->prefixToMode(nick[0]);
987       nick = nick.mid(1);
988     }
989
990     nicks << nick;
991     modes << mode;
992   }
993
994   channel->joinIrcUsers(nicks, modes);
995 }
996
997 /*  RPL_ENDOFWHOWAS - "<nick> :End of WHOWAS" */
998 void IrcServerHandler::handle369(const QString &prefix, const QList<QByteArray> &params) {
999   Q_UNUSED(prefix)
1000   emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whowas] %1").arg(serverDecode(params).join(" ")));
1001 }
1002
1003 /* ERR_ERRONEUSNICKNAME */
1004 void IrcServerHandler::handle432(const QString &prefix, const QList<QByteArray> &params) {
1005   Q_UNUSED(prefix);
1006
1007   QString errnick;
1008   if(params.size() < 2) {
1009     // handle unreal-ircd bug, where unreal ircd doesnt supply a TARGET in ERR_ERRONEUSNICKNAME during registration phase:
1010     // nick @@@
1011     // :irc.scortum.moep.net 432  @@@ :Erroneous Nickname: Illegal characters
1012     // correct server reply:
1013     // :irc.scortum.moep.net 432 * @@@ :Erroneous Nickname: Illegal characters
1014     errnick = target();
1015   } else {
1016     errnick = params[0];
1017   }
1018   emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Nick %1 contains illegal characters").arg(errnick));
1019   tryNextNick(errnick, true /* erroneus */);
1020 }
1021
1022 /* ERR_NICKNAMEINUSE */
1023 void IrcServerHandler::handle433(const QString &prefix, const QList<QByteArray> &params) {
1024   Q_UNUSED(prefix);
1025   if(!checkParamCount("IrcServerHandler::handle433()", params, 1))
1026     return;
1027
1028   QString errnick = serverDecode(params[0]);
1029   emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Nick already in use: %1").arg(errnick));
1030
1031   // if there is a problem while connecting to the server -> we handle it
1032   // but only if our connection has not been finished yet...
1033   if(!network()->currentServer().isEmpty())
1034     return;
1035
1036   tryNextNick(errnick);
1037 }
1038
1039 /* ERR_UNAVAILRESOURCE */
1040 void IrcServerHandler::handle437(const QString &prefix, const QList<QByteArray> &params) {
1041   Q_UNUSED(prefix);
1042   if(!checkParamCount("IrcServerHandler::handle437()", params, 1))
1043     return;
1044
1045   QString errnick = serverDecode(params[0]);
1046   emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Nick/channel is temporarily unavailable: %1").arg(errnick));
1047
1048   // if there is a problem while connecting to the server -> we handle it
1049   // but only if our connection has not been finished yet...
1050   if(!network()->currentServer().isEmpty())
1051     return;
1052
1053   if(!network()->isChannelName(errnick))
1054     tryNextNick(errnick);
1055 }
1056
1057 /* Handle signals from Netsplit objects  */
1058
1059 void IrcServerHandler::handleNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString& quitMessage)
1060 {
1061   IrcChannel *ircChannel = network()->ircChannel(channel);
1062   if(!ircChannel) {
1063     return;
1064   }
1065   QList<IrcUser *> ircUsers;
1066   QStringList newModes = modes;
1067   QStringList newUsers = users;
1068
1069   foreach(QString user, users) {
1070     IrcUser *iu = network()->ircUser(nickFromMask(user));
1071     if(iu)
1072       ircUsers.append(iu);
1073     else { // the user already quit
1074       int idx = users.indexOf(user);
1075       newUsers.removeAt(idx);
1076       newModes.removeAt(idx);
1077     }
1078   }
1079
1080   QString msg = newUsers.join("#:#").append("#:#").append(quitMessage);
1081   emit displayMsg(Message::NetsplitJoin, BufferInfo::ChannelBuffer, channel, msg);
1082   ircChannel->joinIrcUsers(ircUsers, newModes);
1083 }
1084
1085 void IrcServerHandler::handleNetsplitQuit(const QString &channel, const QStringList &users, const QString& quitMessage)
1086 {
1087   QString msg = users.join("#:#").append("#:#").append(quitMessage);
1088   emit displayMsg(Message::NetsplitQuit, BufferInfo::ChannelBuffer, channel, msg);
1089   foreach(QString user, users) {
1090     IrcUser *iu = network()->ircUser(nickFromMask(user));
1091     if(iu)
1092       iu->quit();
1093   }
1094 }
1095
1096 void IrcServerHandler::handleEarlyNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes) {
1097   IrcChannel *ircChannel = network()->ircChannel(channel);
1098   if(!ircChannel) {
1099     qDebug() << "handleEarlyNetsplitJoin(): channel " << channel << " invalid";
1100     return;
1101   }
1102   QList<IrcUser *> ircUsers;
1103   QStringList newModes = modes;
1104
1105   foreach(QString user, users) {
1106     IrcUser *iu = network()->updateNickFromMask(user);
1107     if(iu) {
1108       ircUsers.append(iu);
1109       emit displayMsg(Message::Join, BufferInfo::ChannelBuffer, channel, channel, user);
1110     }
1111     else {
1112       newModes.removeAt(users.indexOf(user));
1113     }
1114   }
1115   ircChannel->joinIrcUsers(ircUsers, newModes);
1116 }
1117 void IrcServerHandler::handleNetsplitFinished()
1118 {
1119   Netsplit* n = qobject_cast<Netsplit*>(sender());
1120   _netsplits.remove(_netsplits.key(n));
1121   n->deleteLater();
1122 }
1123
1124 /* */
1125
1126 // FIXME networkConnection()->setChannelKey("") for all ERR replies indicating that a JOIN went wrong
1127 //       mostly, these are codes in the 47x range
1128
1129 /* */
1130
1131 void IrcServerHandler::tryNextNick(const QString &errnick, bool erroneus) {
1132   QStringList desiredNicks = coreSession()->identity(network()->identity())->nicks();
1133   int nextNickIdx = desiredNicks.indexOf(errnick) + 1;
1134   QString nextNick;
1135   if(nextNickIdx > 0 && desiredNicks.size() > nextNickIdx) {
1136     nextNick = desiredNicks[nextNickIdx];
1137   } else {
1138     if(erroneus) {
1139       emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("No free and valid nicks in nicklist found. use: /nick <othernick> to continue"));
1140       return;
1141     } else {
1142       nextNick = errnick + "_";
1143     }
1144   }
1145   putCmd("NICK", serverEncode(nextNick));
1146 }
1147
1148 bool IrcServerHandler::checkParamCount(const QString &methodName, const QList<QByteArray> &params, int minParams) {
1149   if(params.count() < minParams) {
1150     qWarning() << qPrintable(methodName) << "requires" << minParams << "parameters but received only" << params.count() << serverDecode(params);
1151     return false;
1152   } else {
1153     return true;
1154   }
1155 }
1156
1157 void IrcServerHandler::destroyNetsplits() {
1158   qDeleteAll(_netsplits);
1159   _netsplits.clear();
1160 }
1161
1162 #ifdef HAVE_QCA2
1163 QByteArray IrcServerHandler::decrypt(const QString &bufferName, const QByteArray &message_, bool isTopic) {
1164   if(message_.isEmpty())
1165     return message_;
1166
1167   Cipher *cipher = network()->cipher(bufferName);
1168   if(!cipher)
1169     return message_;
1170
1171   QByteArray message = message_;
1172   message = isTopic? cipher->decryptTopic(message) : cipher->decrypt(message);
1173   return message;
1174 }
1175 #endif