X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fcoreuserinputhandler.cpp;h=95605bdb31d443f56fcfcb9131bd29eca19ed3c7;hp=a2feda9aa91f51072c2822957ef93b96dc5aa0ce;hb=82a12eca7978598dafc059df6a2156e8899ef942;hpb=ca8f178da7892a9b8b16a4c9bac286b15c2a53d5 diff --git a/src/core/coreuserinputhandler.cpp b/src/core/coreuserinputhandler.cpp index a2feda9a..95605bdb 100644 --- a/src/core/coreuserinputhandler.cpp +++ b/src/core/coreuserinputhandler.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * 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 * @@ -28,8 +28,12 @@ #include #include +#ifdef HAVE_QCA2 +#include "cipher.h" +#endif + CoreUserInputHandler::CoreUserInputHandler(CoreNetwork *parent) - : BasicHandler(parent) + : CoreBasicHandler(parent) { } @@ -51,14 +55,31 @@ void CoreUserInputHandler::handleUserInput(const BufferInfo &bufferInfo, const Q // ==================== void CoreUserInputHandler::handleAway(const BufferInfo &bufferInfo, const QString &msg) { Q_UNUSED(bufferInfo) + if(msg.startsWith("-all")) { + if(msg.length() == 4) { + coreSession()->globalAway(); + return; + } + Q_ASSERT(msg.length() > 4); + if(msg[4] == ' ') { + coreSession()->globalAway(msg.mid(5)); + return; + } + } + issueAway(msg); +} +void CoreUserInputHandler::issueAway(const QString &msg, bool autoCheck) { QString awayMsg = msg; IrcUser *me = network()->me(); // if there is no message supplied we have to check if we are already away or not - if(msg.isEmpty()) { + if(autoCheck && msg.isEmpty()) { if(me && !me->isAway()) { - awayMsg = network()->identityPtr()->awayReason(); + Identity *identity = network()->identityPtr(); + if(identity) { + awayMsg = identity->awayReason(); + } if(awayMsg.isEmpty()) { awayMsg = tr("away"); } @@ -128,8 +149,8 @@ void CoreUserInputHandler::handleCtcp(const BufferInfo &bufferInfo, const QStrin if(ctcpTag.isEmpty()) return; - QString message = ""; - QString verboseMessage = tr("sending CTCP-%1 request").arg(ctcpTag); + QString message = msg.section(' ', 2); + QString verboseMessage = tr("sending CTCP-%1 request to %2").arg(ctcpTag).arg(nick); if(ctcpTag == "PING") { uint now = QDateTime::currentDateTime().toTime_t(); @@ -140,6 +161,60 @@ void CoreUserInputHandler::handleCtcp(const BufferInfo &bufferInfo, const QStrin emit displayMsg(Message::Action, BufferInfo::StatusBuffer, "", verboseMessage, network()->myNick()); } +void CoreUserInputHandler::handleDelkey(const BufferInfo &bufferInfo, const QString &msg) { + #ifdef HAVE_QCA2 + if (!bufferInfo.isValid()) + return; + + QStringList parms = msg.split(' ', QString::SkipEmptyParts); + + if(parms.isEmpty() && !bufferInfo.bufferName().isEmpty()) + parms.prepend(bufferInfo.bufferName()); + + if(parms.isEmpty()) { + QString message = tr("[usage] /delkey deletes the encryption key for nick or channel or just /delkey when in a channel or query."); + + if(bufferInfo.bufferName().isEmpty()) + emit displayMsg(Message::Info, BufferInfo::StatusBuffer, "", message); + else + emit displayMsg(Message::Info, bufferInfo.bufferName(), message); + return; + } + + if(network()->bufferKey(parms[0]).isEmpty()) { + QString message = tr("No key has been set for %1.").arg(parms[0]); + + if(bufferInfo.bufferName().isEmpty()) + emit displayMsg(Message::Info, BufferInfo::StatusBuffer, "", message); + else + emit displayMsg(Message::Info, bufferInfo.bufferName(), message); + return; + } + + network()->setBufferKey(parms[0], ""); + + if(network()->isChannelName(parms[0]) && network()->channels().contains(parms[0])) { + network()->ircChannel(parms[0])->setEncrypted(false); + } + else if(network()->nicks().contains(parms[0])) { + network()->ircUser(parms[0])->setEncrypted(false); + } + + QString message = tr("The key for %1 has been deleted.").arg(parms[0]); + + if(bufferInfo.bufferName().isEmpty()) + emit displayMsg(Message::Info, BufferInfo::StatusBuffer, "", message); + else + emit displayMsg(Message::Info, bufferInfo.bufferName(), message); + + #else + emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Error: Setting an encryption key requires Quassel to have been built " + "with support for the Qt Cryptographic Architecture (QCA) library. " + "Contact your distributor about a Quassel package with QCA " + "support, or rebuild Quassel with QCA present.")); + #endif +} + void CoreUserInputHandler::handleDeop(const BufferInfo &bufferInfo, const QString &msg) { QStringList nicks = msg.split(' ', QString::SkipEmptyParts); QString m = "-"; for(int i = 0; i < nicks.count(); i++) m += 'o'; @@ -169,16 +244,23 @@ void CoreUserInputHandler::handleJoin(const BufferInfo &bufferInfo, const QStrin QString sane_msg = msg; sane_msg.replace(QRegExp(", +"), ","); QStringList params = sane_msg.trimmed().split(" "); + QStringList chans = params[0].split(",", QString::SkipEmptyParts); QStringList keys; + if(params.count() > 1) + keys = params[1].split(","); + int i; for(i = 0; i < chans.count(); i++) { if(!network()->isChannelName(chans[i])) chans[i].prepend('#'); - } - if(params.count() > 1) - keys = params[1].split(","); + if(i < keys.count()) { + network()->addChannelKey(chans[i], keys[i]); + } else { + network()->removeChannelKey(chans[i]); + } + } static const char *cmd = "JOIN"; i = 0; @@ -186,18 +268,24 @@ void CoreUserInputHandler::handleJoin(const BufferInfo &bufferInfo, const QStrin int slicesize = chans.count(); QList encodedParams; + // go through all to-be-joined channels and (re)build the join list while(i < chans.count()) { joinChans.append(chans.at(i)); if(i < keys.count()) joinKeys.append(keys.at(i)); + // if the channel list we built so far either contains all requested channels or exceeds + // the desired amount of channels in this slice, try to send what we have so far if(++i == chans.count() || joinChans.count() >= slicesize) { - params[0] = joinChans.join(","); - params[1] = joinKeys.join(","); + params.clear(); + params.append(joinChans.join(",")); + params.append(joinKeys.join(",")); encodedParams = serverEncode(params); + // check if it fits in one command if(lastParamOverrun(cmd, encodedParams) == 0) { emit putCmd(cmd, encodedParams); } else if(slicesize > 1) { + // back to start of slice, try again with half the amount of channels i -= slicesize; slicesize /= 2; } @@ -205,16 +293,6 @@ void CoreUserInputHandler::handleJoin(const BufferInfo &bufferInfo, const QStrin joinKeys.clear(); } } - - i = 0; - for(; i < keys.count(); i++) { - if(i >= chans.count()) - break; - network()->addChannelKey(chans[i], keys[i]); - } - for(; i < chans.count(); i++) { - network()->removeChannelKey(chans[i]); - } } void CoreUserInputHandler::handleKick(const BufferInfo &bufferInfo, const QString &msg) { @@ -254,8 +332,17 @@ void CoreUserInputHandler::handleMode(const BufferInfo &bufferInfo, const QStrin QStringList params = msg.split(' ', QString::SkipEmptyParts); // if the first argument is neither a channel nor us (user modes are only to oneself) the current buffer is assumed to be the target - if(!params.isEmpty() && !network()->isChannelName(params[0]) && !network()->isMyNick(params[0])) - params.prepend(bufferInfo.bufferName()); + if(!params.isEmpty()) { + if(!network()->isChannelName(params[0]) && !network()->isMyNick(params[0])) + params.prepend(bufferInfo.bufferName()); + if(network()->isMyNick(params[0]) && params.count() == 2) + network()->updateIssuedModes(params[1]); + if(params[0] == "-reset" && params.count() == 1) { + // FIXME: give feedback to the user (I don't want to add new strings right now) + network()->resetPersistentModes(); + return; + } + } // TODO handle correct encoding for buffer modes (channelEncode()) emit putCmd("MODE", serverEncode(params)); @@ -268,7 +355,7 @@ void CoreUserInputHandler::handleMsg(const BufferInfo &bufferInfo, const QString return; QByteArray target = serverEncode(msg.section(' ', 0, 0)); - putPrivmsg(target, userEncode(target, msg.section(' ', 1))); + putPrivmsg(target, userEncode(target, msg.section(' ', 1)), false); } void CoreUserInputHandler::handleNick(const BufferInfo &bufferInfo, const QString &msg) { @@ -358,16 +445,62 @@ void CoreUserInputHandler::handleQuote(const BufferInfo &bufferInfo, const QStri void CoreUserInputHandler::handleSay(const BufferInfo &bufferInfo, const QString &msg) { if(bufferInfo.bufferName().isEmpty()) return; // server buffer - putPrivmsg(serverEncode(bufferInfo.bufferName()), channelEncode(bufferInfo.bufferName(), msg)); + putPrivmsg(serverEncode(bufferInfo.bufferName()), channelEncode(bufferInfo.bufferName(), msg), false); emit displayMsg(Message::Plain, bufferInfo.type(), bufferInfo.bufferName(), msg, network()->myNick(), Message::Self); } +void CoreUserInputHandler::handleSetkey(const BufferInfo &bufferInfo, const QString &msg) { + #ifdef HAVE_QCA2 + if(!bufferInfo.isValid()) + return; + + QStringList parms = msg.split(' ', QString::SkipEmptyParts); + + if(parms.count() == 1 && !bufferInfo.bufferName().isEmpty()) + parms.prepend(bufferInfo.bufferName()); + else if(parms.count() != 2) { + QString message =tr("[usage] /setkey sets the encryption key for nick or channel. /setkey when in a channel or query buffer sets the key for it."); + + if(bufferInfo.bufferName().isEmpty()) + emit displayMsg(Message::Info, BufferInfo::StatusBuffer, "", message); + else + emit displayMsg(Message::Info, bufferInfo.bufferName(), message); + return; + } + network()->setBufferKey(parms[0], parms[1].toLocal8Bit()); + + if(network()->isChannelName(parms[0]) && network()->channels().contains(parms[0])) + network()->ircChannel(parms[0])->setEncrypted(true); + else if(network()->nicks().contains(parms[0])) + network()->ircUser(parms[0])->setEncrypted(true); + + QString message = tr("The key for %1 has been set.").arg(parms[0]); + if (bufferInfo.bufferName().isEmpty()) + emit displayMsg(Message::Info, BufferInfo::StatusBuffer, "", message); + else + emit displayMsg(Message::Info, bufferInfo.bufferName(), message); + #else + emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Error: Setting an encryption key requires Quassel to have been built " + "with support for the Qt Cryptographic Architecture (QCA) library. " + "Contact your distributor about a Quassel package with QCA " + "support, or rebuild Quassel with QCA present.")); + #endif +} + void CoreUserInputHandler::handleTopic(const BufferInfo &bufferInfo, const QString &msg) { if(bufferInfo.bufferName().isEmpty()) return; QList params; params << serverEncode(bufferInfo.bufferName()); - if(!msg.isEmpty()) + if(!msg.isEmpty()) { + #ifdef HAVE_QCA2 + const QByteArray bufferName = bufferInfo.bufferName().toAscii(); + QByteArray message = channelEncode(bufferInfo.bufferName(), msg); + params << encrypt(bufferName, message); + #else params << channelEncode(bufferInfo.bufferName(), msg); + #endif + } + emit putCmd("TOPIC", params); } @@ -415,27 +548,37 @@ void CoreUserInputHandler::handleWhowas(const BufferInfo &bufferInfo, const QStr void CoreUserInputHandler::defaultHandler(QString cmd, const BufferInfo &bufferInfo, const QString &msg) { Q_UNUSED(bufferInfo); - emit putCmd(serverEncode(cmd.toUpper()), serverEncode(msg)); + emit putCmd(serverEncode(cmd.toUpper()), serverEncode(msg.split(" "))); } -void CoreUserInputHandler::putPrivmsg(const QByteArray &target, const QByteArray &message) { +void CoreUserInputHandler::putPrivmsg(const QByteArray &target, const QByteArray &message, bool encrypted) { + + QByteArray temp = message; + + #ifdef HAVE_QCA2 + if(!encrypted) { + temp = encrypt(target, temp); + encrypted = true; + } + #endif + static const char *cmd = "PRIVMSG"; - int overrun = lastParamOverrun(cmd, QList() << target << message); + int overrun = lastParamOverrun(cmd, QList() << target << temp); if(overrun) { static const char *splitter = " .,-"; - int maxSplitPos = message.count() - overrun; + int maxSplitPos = temp.count() - overrun; int splitPos = -1; for(const char *splitChar = splitter; *splitChar != 0; splitChar++) { - splitPos = qMax(splitPos, message.lastIndexOf(*splitChar, maxSplitPos)); + splitPos = qMax(splitPos, temp.lastIndexOf(*splitChar, maxSplitPos)); } if(splitPos <= 0) { splitPos = maxSplitPos; } - putCmd(cmd, QList() << target << message.left(splitPos)); - putPrivmsg(target, message.mid(splitPos)); + putCmd(cmd, QList() << target << temp.left(splitPos)); + putPrivmsg(target, temp.mid(splitPos), encrypted); return; } else { - putCmd(cmd, QList() << target << message); + putCmd(cmd, QList() << target << temp); } } @@ -468,6 +611,30 @@ int CoreUserInputHandler::lastParamOverrun(const QString &cmd, const QListbufferKey(target); + if(key.isEmpty()) + return message; + + IrcChannel *channel = network()->ircChannel(target); + IrcUser *user = network()->ircUser(target); + + if(channel && channel->cipher()->setKey(key)) + channel->cipher()->encrypt(message); + else if(user && user->cipher()->setKey(key)) + user->cipher()->encrypt(message); + + return message; +} +#endif + void CoreUserInputHandler::timerEvent(QTimerEvent *event) { if(!_delayedCommands.contains(event->timerId())) { QObject::timerEvent(event);