/***************************************************************************
- * Copyright (C) 2005-09 by the Quassel Project *
+ * Copyright (C) 2005-10 by the Quassel Project *
* devel@quassel-irc.org *
* *
* This program is free software; you can redistribute it and/or modify *
#include <QDebug>
+#ifdef HAVE_QCA2
+#include "cipher.h"
+#endif
+
IrcServerHandler::IrcServerHandler(CoreNetwork *parent)
- : BasicHandler(parent),
+ : CoreBasicHandler(parent),
_whois(false)
{
+ connect(parent, SIGNAL(disconnected(NetworkId)), this, SLOT(destroyNetsplits()));
}
IrcServerHandler::~IrcServerHandler() {
- if(!_netsplits.empty())
- qDeleteAll(_netsplits);
+ destroyNetsplits();
}
/*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */
QString foo = serverDecode(params.takeFirst());
+ // with SASL, the command is 'AUTHENTICATE +' and we should check for this here.
+ if(foo == QString("AUTHENTICATE +")) {
+ handleAuthenticate();
+ return;
+ }
+
// a colon as the first chars indicates the existence of a prefix
if(foo[0] == ':') {
foo.remove(0, 1);
case 321: case 366: case 376:
break;
+ case 903: case 904: case 905: case 906: case 907:
+ {
+ network()->putRawLine("CAP END");
+ emit displayMsg(Message::Info, BufferInfo::StatusBuffer, "", "CAP: " + params.join(""));
+ }
// Everything else will be marked in red, so we can add them somewhere.
default:
if(_whois) {
if(!removeModes.isEmpty())
ircUser->removeUserModes(removeModes);
+ if(network()->isMe(ircUser)) {
+ network()->updatePersistentModes(addModes, removeModes);
+ }
+
// FIXME: redirect
emit displayMsg(Message::Mode, BufferInfo::StatusBuffer, "", serverDecode(params).join(" "), prefix);
}
? *targetIter
: senderNick;
+ #ifdef HAVE_QCA2
+ msg = decrypt(target, msg);
+ #endif
// it's possible to pack multiple privmsgs into one param using ctcp
// - > we let the ctcpHandler do the work
network()->ctcpHandler()->parse(Message::Plain, prefix, target, msg);
return;
QString topic;
- if(params.count() > 1)
- topic = channelDecode(channel->name(), params[1]);
-
+ if(params.count() > 1) {
+ topic = params[1];
+ #ifdef HAVE_QCA2
+ topic = decryptTopic(channel->name(), topic);
+ #endif
+ }
+
channel->setTopic(topic);
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));
}
+void IrcServerHandler::handleCap(const QString &prefix, const QList<QByteArray> ¶ms) {
+ // for SASL, there will only be a single param of 'sasl', however you can check here for
+ // additional CAP messages (ls, multi-prefix, et cetera).
+
+ Q_UNUSED(prefix);
+
+ if(params.size() == 3) {
+ QString param = serverDecode(params[2]);
+ if(param == QString("sasl")) { // SASL Ready
+ network()->putRawLine(serverEncode("AUTHENTICATE PLAIN")); // Only working with PLAIN atm, blowfish later
+ }
+ }
+}
+
+void IrcServerHandler::handleAuthenticate() {
+ QString construct = network()->saslAccount();
+ construct.append(QChar(QChar::Null));
+ construct.append(network()->saslAccount());
+ construct.append(QChar(QChar::Null));
+ construct.append(network()->saslPassword());
+ QByteArray saslData = QByteArray(construct.toAscii().toBase64());
+ saslData.prepend(QString("AUTHENTICATE ").toAscii());
+ network()->putRawLine(saslData);
+}
+
/* RPL_WELCOME */
void IrcServerHandler::handle001(const QString &prefix, const QList<QByteArray> ¶ms) {
network()->setCurrentServer(prefix);
QString channel = serverDecode(params[0]);
QString topic = channelDecode(channel, params[1]);
+
+ #ifdef HAVE_QCA2
+ topic = decryptTopic(channel, topic);
+ #endif
+
IrcChannel *chan = network()->ircChannel(channel);
if(chan)
chan->setTopic(topic);
tryNextNick(errnick);
}
+/* ERR_UNAVAILRESOURCE */
+void IrcServerHandler::handle437(const QString &prefix, const QList<QByteArray> ¶ms) {
+ Q_UNUSED(prefix);
+ if(!checkParamCount("IrcServerHandler::handle437()", params, 1))
+ return;
+
+ QString errnick = serverDecode(params[0]);
+ emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Nick/channel is temporarily unavailable: %1").arg(errnick));
+
+ // if there is a problem while connecting to the server -> we handle it
+ // but only if our connection has not been finished yet...
+ if(!network()->currentServer().isEmpty())
+ return;
+
+ if(!network()->isChannelName(errnick))
+ tryNextNick(errnick);
+}
+
/* Handle signals from Netsplit objects */
void IrcServerHandler::handleNetsplitJoin(const QString &channel, const QStringList &users, const QStringList &modes, const QString& quitMessage)
}
QList<IrcUser *> ircUsers;
QStringList newModes = modes;
+ QStringList newUsers = users;
foreach(QString user, users) {
- IrcUser *iu = network()->updateNickFromMask(user);
+ IrcUser *iu = network()->ircUser(nickFromMask(user));
if(iu)
ircUsers.append(iu);
- else {
- newModes.removeAt(users.indexOf(user));
+ else { // the user already quit
+ int idx = users.indexOf(user);
+ newUsers.removeAt(idx);
+ newModes.removeAt(idx);
}
}
- QString msg = users.join("#:#").append("#:#").append(quitMessage);
+ QString msg = newUsers.join("#:#").append("#:#").append(quitMessage);
emit displayMsg(Message::NetsplitJoin, BufferInfo::ChannelBuffer, channel, msg);
ircChannel->joinIrcUsers(ircUsers, newModes);
}
}
}
+void IrcServerHandler::destroyNetsplits() {
+ qDeleteAll(_netsplits);
+ _netsplits.clear();
+}
+
+#ifdef HAVE_QCA2
+QByteArray IrcServerHandler::decrypt(const QString &bufferName, QByteArray &message) {
+ if(bufferName.isEmpty())
+ return message;
+
+ if(message.isEmpty())
+ return message;
+
+ const QByteArray key = network()->bufferKey(bufferName);
+ if(key.isEmpty())
+ return message;
+
+ IrcChannel *channel = network()->ircChannel(bufferName);
+ IrcUser *user = network()->ircUser(bufferName);
+
+ //only send encrypted text to decrypter
+ int index = message.indexOf(":",message.indexOf(":")+1);
+
+ /* if(this->identifyMsgEnabled()) // Workaround braindead Freenode prefixing messages with +
+ ++index;*/
+
+ QByteArray backup = message.mid(0,index+1);
+
+ if (channel && channel->cipher()->setKey(key))
+ message = channel->cipher()->decrypt(message.mid(index+1));
+ else if (user && user->cipher()->setKey(key))
+ message = user->cipher()->decrypt(message.mid(index+1));
+
+ message.prepend(backup);
+
+ message = channelDecode(bufferName, message).toAscii();
+
+ return message;
+}
+
+QString IrcServerHandler::decryptTopic(const QString &bufferName, QString &topic) {
+ if(bufferName.isEmpty())
+ return topic;
+
+ if(topic.isEmpty())
+ return topic;
+
+ const QByteArray key = network()->bufferKey(bufferName);
+ if(key.isEmpty())
+ return topic;
+
+ IrcChannel *channel = network()->ircChannel(bufferName);
+ IrcUser *user = network()->ircUser(bufferName);
+
+ //only send encrypted text to decrypter
+ int index = topic.indexOf(":",topic.indexOf(":")+1);
+
+ QString backup = topic.mid(0,index+1);
+
+ if (channel && channel->cipher()->setKey(key))
+ topic = channel->cipher()->decryptTopic(topic.mid(index+1).toAscii());
+ else if (user && user->cipher()->setKey(key))
+ topic = user->cipher()->decryptTopic(topic.mid(index+1).toAscii());
+
+ topic.prepend(backup);
+ topic = channelDecode(bufferName, topic.toAscii());
+
+ return topic;
+}
+#endif
/***********************************************************************************/