/***************************************************************************
- * 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) {
//******************************/
// IRC SERVER HANDLER
//******************************/
+void IrcServerHandler::handleInvite(const QString &prefix, const QList<QByteArray> ¶ms) {
+ if(!checkParamCount("IrcServerHandler::handleInvite()", params, 2))
+ return;
+// qDebug() << "IrcServerHandler::handleInvite()" << prefix << params;
+
+ IrcUser *ircuser = network()->updateNickFromMask(prefix);
+ if(!ircuser) {
+ return;
+ }
+
+ QString channel = serverDecode(params[1]);
+
+ emit displayMsg(Message::Invite, BufferInfo::StatusBuffer, "", tr("%1 invited you to channel %2").arg(ircuser->nick()).arg(channel));
+}
+
void IrcServerHandler::handleJoin(const QString &prefix, const QList<QByteArray> ¶ms) {
if(!checkParamCount("IrcServerHandler::handleJoin()", params, 1))
return;
// user channel modes (op, voice, etc...)
if(paramOffset < params.count()) {
IrcUser *ircUser = network()->ircUser(params[paramOffset]);
- if(add) {
- bool handledByNetsplit = false;
- if(!_netsplits.empty()) {
- foreach(Netsplit* n, _netsplits) {
- handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name());
- if(handledByNetsplit) {
- n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c]));
- break;
+ if(!ircUser) {
+ qWarning() << Q_FUNC_INFO << "Unknown IrcUser:" << params[paramOffset];
+ } else {
+ if(add) {
+ bool handledByNetsplit = false;
+ if(!_netsplits.empty()) {
+ foreach(Netsplit* n, _netsplits) {
+ handledByNetsplit = n->userAlreadyJoined(ircUser->hostmask(), channel->name());
+ if(handledByNetsplit) {
+ n->addMode(ircUser->hostmask(), channel->name(), QString(modes[c]));
+ break;
+ }
}
}
+ if(!handledByNetsplit)
+ channel->addUserMode(ircUser, QString(modes[c]));
}
- if(!handledByNetsplit)
- channel->addUserMode(ircUser, QString(modes[c]));
+ else
+ channel->removeUserMode(ircUser, QString(modes[c]));
}
- else
- channel->removeUserMode(ircUser, QString(modes[c]));
} else {
qWarning() << "Received MODE with too few parameters:" << serverDecode(params);
}
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) {
+ QByteArray rawTopic = params[1];
+#ifdef HAVE_QCA2
+ rawTopic = decrypt(channel->name(), rawTopic, true);
+#endif
+ topic = channelDecode(channel->name(), rawTopic);
+ }
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 value = rawSupport.section("=", 1);
network()->addSupport(key, value);
}
+
+ /* determine our prefixes here to get an accurate result */
+ network()->determinePrefixes();
}
/* RPL_UMODEIS - "<user_modes> [<user_mode_params>]" */
ircuser->setRealName(serverDecode(params.last()));
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is %2 (%3)") .arg(ircuser->nick()).arg(ircuser->hostmask()).arg(ircuser->realName()));
} else {
- emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is %2 (%3)") .arg(serverDecode(params[1])).arg(serverDecode(params[2])).arg(serverDecode(params.last())));
+ QString host = QString("%1!%2@%3").arg(serverDecode(params[0])).arg(serverDecode(params[1])).arg(serverDecode(params[2]));
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is %2 (%3)") .arg(serverDecode(params[0])).arg(host).arg(serverDecode(params.last())));
}
}
QString nick = serverDecode(params[0]);
IrcUser *ircuser = network()->ircUser(nick);
+
+ QDateTime now = QDateTime::currentDateTime();
+ int idleSecs = serverDecode(params[1]).toInt();
+ idleSecs *= -1;
+
if(ircuser) {
- QDateTime now = QDateTime::currentDateTime();
- int idleSecs = serverDecode(params[1]).toInt();
- idleSecs *= -1;
ircuser->setIdleTime(now.addSecs(idleSecs));
if(params.size() > 3) { // if we have more then 3 params we have the above mentioned "real life" situation
int loginTime = serverDecode(params[2]).toInt();
emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is logged in since %2").arg(ircuser->nick()).arg(ircuser->loginTime().toString()));
}
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()));
-
} else {
- emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] idle message: %1").arg(userDecode(nick, params).join(" ")));
+ QDateTime idleSince = now.addSecs(idleSecs);
+ if (params.size() > 3) { // we have a signon time
+ int loginTime = serverDecode(params[2]).toInt();
+ QDateTime datetime = QDateTime::fromTime_t(loginTime);
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is logged in since %2").arg(nick).arg(datetime.toString()));
+ }
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is idling for %2 (%3)").arg(nick).arg(secondsToString(idleSince.secsTo(now))).arg(idleSince.toString()));
}
}
emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel, tr("Channel %1 created on %2").arg(channel, time.toString()));
}
+/* RPL_WHOISACCOUNT: "<nick> <account> :is authed as */
+void IrcServerHandler::handle330(const QString &prefix, const QList<QByteArray> ¶ms) {
+ Q_UNUSED(prefix);
+ if(!checkParamCount("IrcServerHandler::handle330()", params, 3))
+ return;
+
+ QString nick = serverDecode(params[0]);
+ QString account = serverDecode(params[1]);
+
+ emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("[Whois] %1 is authed as %2").arg(nick).arg(account));
+}
+
/* RPL_NOTOPIC */
void IrcServerHandler::handle331(const QString &prefix, const QList<QByteArray> ¶ms) {
Q_UNUSED(prefix);
return;
QString channel = serverDecode(params[0]);
- QString topic = channelDecode(channel, params[1]);
+ QByteArray rawTopic = params[1];
+#ifdef HAVE_QCA2
+ rawTopic = decrypt(channel, rawTopic, true);
+#endif
+ QString topic = channelDecode(channel, rawTopic);
+
IrcChannel *chan = network()->ircChannel(channel);
if(chan)
chan->setTopic(topic);
tr("Topic set by %1 on %2") .arg(serverDecode(params[1]), QDateTime::fromTime_t(channelDecode(channel, params[2]).toUInt()).toString()));
}
+/* RPL_INVITING - "<nick> <channel>*/
+void IrcServerHandler::handle341(const QString &prefix, const QList<QByteArray> ¶ms) {
+ Q_UNUSED(prefix);
+ if(!checkParamCount("IrcServerHandler::handle341()", params, 2))
+ return;
+
+ QString nick = serverDecode(params[0]);
+
+ IrcChannel *channel = network()->ircChannel(serverDecode(params[1]));
+ if(!channel) {
+ qWarning() << "IrcServerHandler::handle341(): unknown channel:" << params[1];
+ return;
+ }
+
+ emit displayMsg(Message::Server, BufferInfo::ChannelBuffer, channel->name(), tr("%1 has been invited to %2").arg(nick).arg(channel->name()));
+}
+
/* RPL_WHOREPLY: "<channel> <user> <host> <server> <nick>
( "H" / "G" > ["*"] [ ( "@" / "+" ) ] :<hopcount> <real name>" */
void IrcServerHandler::handle352(const QString &prefix, const QList<QByteArray> ¶ms) {
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, const QByteArray &message_, bool isTopic) {
+ if(message_.isEmpty())
+ return message_;
+ Cipher *cipher = network()->cipher(bufferName);
+ if(!cipher)
+ return message_;
+ QByteArray message = message_;
+ message = isTopic? cipher->decryptTopic(message) : cipher->decrypt(message);
+ return message;
+}
+#endif