X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fctcphandler.cpp;h=56f8b3329120386b479a95f8c2ca7f3a65f0b4a5;hp=e7f1e302da19f3c7f810afa7fba2c3cedab0934c;hb=36ea1791352d34e34b6c6cdef02455a4c43acc17;hpb=5b560ec1a01349562ac58051ca7e7fa899d4b994 diff --git a/src/core/ctcphandler.cpp b/src/core/ctcphandler.cpp index e7f1e302..56f8b332 100644 --- a/src/core/ctcphandler.cpp +++ b/src/core/ctcphandler.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-08 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 * @@ -19,34 +19,53 @@ ***************************************************************************/ #include "ctcphandler.h" -#include "global.h" -#include "util.h" #include "message.h" #include "network.h" +#include "quassel.h" +#include "util.h" +#include "coreignorelistmanager.h" -CtcpHandler::CtcpHandler(NetworkConnection *parent) - : BasicHandler(parent) { +CtcpHandler::CtcpHandler(CoreNetwork *parent) + : CoreBasicHandler(parent), + XDELIM("\001"), + _ignoreListManager(parent->ignoreListManager()) +{ - QString MQUOTE = QString('\020'); - ctcpMDequoteHash[MQUOTE + '0'] = QString('\000'); - ctcpMDequoteHash[MQUOTE + 'n'] = QString('\n'); - ctcpMDequoteHash[MQUOTE + 'r'] = QString('\r'); + QByteArray MQUOTE = QByteArray("\020"); + ctcpMDequoteHash[MQUOTE + '0'] = QByteArray(1, '\000'); + ctcpMDequoteHash[MQUOTE + 'n'] = QByteArray(1, '\n'); + ctcpMDequoteHash[MQUOTE + 'r'] = QByteArray(1, '\r'); ctcpMDequoteHash[MQUOTE + MQUOTE] = MQUOTE; - XDELIM = QString('\001'); - QString XQUOTE = QString('\134'); + QByteArray XQUOTE = QByteArray("\134"); ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE; - ctcpXDelimDequoteHash[XQUOTE + QString('a')] = XDELIM; + ctcpXDelimDequoteHash[XQUOTE + QByteArray("a")] = XDELIM; } -QString CtcpHandler::dequote(QString message) { - QString dequotedMessage; - QString messagepart; - QHash::iterator ctcpquote; - +QByteArray CtcpHandler::lowLevelQuote(const QByteArray &message) { + QByteArray quotedMessage = message; + + QHash quoteHash = ctcpMDequoteHash; + QByteArray MQUOTE = QByteArray("\020"); + quoteHash.remove(MQUOTE + MQUOTE); + quotedMessage.replace(MQUOTE, MQUOTE + MQUOTE); + + QHash::const_iterator quoteIter = quoteHash.constBegin(); + while(quoteIter != quoteHash.constEnd()) { + quotedMessage.replace(quoteIter.value(), quoteIter.key()); + quoteIter++; + } + return quotedMessage; +} + +QByteArray CtcpHandler::lowLevelDequote(const QByteArray &message) { + QByteArray dequotedMessage; + QByteArray messagepart; + QHash::iterator ctcpquote; + // copy dequote Message for(int i = 0; i < message.size(); i++) { - messagepart = message[i]; + messagepart = message.mid(i,1); if(i+1 < message.size()) { for(ctcpquote = ctcpMDequoteHash.begin(); ctcpquote != ctcpMDequoteHash.end(); ++ctcpquote) { if(message.mid(i,2) == ctcpquote.key()) { @@ -61,14 +80,23 @@ QString CtcpHandler::dequote(QString message) { return dequotedMessage; } +QByteArray CtcpHandler::xdelimQuote(const QByteArray &message) { + QByteArray quotedMessage = message; + QHash::const_iterator quoteIter = ctcpXDelimDequoteHash.constBegin(); + while(quoteIter != ctcpXDelimDequoteHash.constEnd()) { + quotedMessage.replace(quoteIter.value(), quoteIter.key()); + quoteIter++; + } + return quotedMessage; +} -QString CtcpHandler::XdelimDequote(QString message) { - QString dequotedMessage; - QString messagepart; - QHash::iterator xdelimquote; +QByteArray CtcpHandler::xdelimDequote(const QByteArray &message) { + QByteArray dequotedMessage; + QByteArray messagepart; + QHash::iterator xdelimquote; for(int i = 0; i < message.size(); i++) { - messagepart = message[i]; + messagepart = message.mid(i,1); if(i+1 < message.size()) { for(xdelimquote = ctcpXDelimDequoteHash.begin(); xdelimquote != ctcpXDelimDequoteHash.end(); ++xdelimquote) { if(message.mid(i,2) == xdelimquote.key()) { @@ -83,93 +111,174 @@ QString CtcpHandler::XdelimDequote(QString message) { return dequotedMessage; } -void CtcpHandler::parse(Message::Type messageType, QString prefix, QString target, QString message) { - QString ctcp; - +void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const QString &target, const QByteArray &message) { + QByteArray ctcp; + //lowlevel message dequote - QString dequotedMessage = dequote(message); + QByteArray dequotedMessage = lowLevelDequote(message); - CtcpType ctcptype = (messageType == Message::Notice) + CtcpType ctcptype = messageType == Message::Notice ? CtcpReply : CtcpQuery; - BufferInfo::Type bufferType = typeByTarget(target); - + Message::Flags flags = (messageType == Message::Notice && !network()->isChannelName(target)) + ? Message::Redirected + : Message::None; + // extract tagged / extended data - while(dequotedMessage.contains(XDELIM)) { - if(dequotedMessage.indexOf(XDELIM) > 0) - emit displayMsg(messageType, bufferType, target, dequotedMessage.section(XDELIM,0,0), prefix); - // messages << dequotedMessage.section(XDELIM,0,0), prefix); - ctcp = XdelimDequote(dequotedMessage.section(XDELIM,1,1)); - dequotedMessage = dequotedMessage.section(XDELIM,2,2); - + int xdelimPos = -1; + int xdelimEndPos = -1; + int spacePos = -1; + QList replies; + while((xdelimPos = dequotedMessage.indexOf(XDELIM)) != -1) { + if(xdelimPos > 0) + displayMsg(messageType, target, userDecode(target, dequotedMessage.left(xdelimPos)), prefix, flags); + + xdelimEndPos = dequotedMessage.indexOf(XDELIM, xdelimPos + 1); + if(xdelimEndPos == -1) { + // no matching end delimiter found... treat rest of the message as ctcp + xdelimEndPos = dequotedMessage.count(); + } + ctcp = xdelimDequote(dequotedMessage.mid(xdelimPos + 1, xdelimEndPos - xdelimPos - 1)); + dequotedMessage = dequotedMessage.mid(xdelimEndPos + 1); + //dispatch the ctcp command - QString ctcpcmd = ctcp.section(' ', 0, 0); - QString ctcpparam = ctcp.section(' ', 1); + QString ctcpcmd = userDecode(target, ctcp.left(spacePos)); + QString ctcpparam = userDecode(target, ctcp.mid(spacePos + 1)); + + spacePos = ctcp.indexOf(' '); + if(spacePos != -1) { + ctcpcmd = userDecode(target, ctcp.left(spacePos)); + ctcpparam = userDecode(target, ctcp.mid(spacePos + 1)); + } else { + ctcpcmd = userDecode(target, ctcp); + ctcpparam = QString(); + } - handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam)); + if(!_ignoreListManager->ctcpMatch(prefix, network()->networkName(), ctcpcmd.toUpper())) { + QString reply_; + handle(ctcpcmd, Q_ARG(CtcpType, ctcptype), Q_ARG(QString, prefix), Q_ARG(QString, target), Q_ARG(QString, ctcpparam), Q_ARG(QString, reply_)); + if(ctcptype == CtcpQuery && !reply_.isNull()) { + replies << lowLevelQuote(pack(serverEncode(ctcpcmd), userEncode(nickFromMask(prefix), reply_))); + } + } + } + if(ctcptype == CtcpQuery && !replies.isEmpty()) { + packedReply(nickFromMask(prefix), replies); } - + if(!dequotedMessage.isEmpty()) - emit displayMsg(messageType, bufferType, target, dequotedMessage, prefix); + displayMsg(messageType, target, userDecode(target, dequotedMessage), prefix, flags); +} +QByteArray CtcpHandler::pack(const QByteArray &ctcpTag, const QByteArray &message) { + if(message.isEmpty()) + return XDELIM + ctcpTag + XDELIM; + + return XDELIM + ctcpTag + ' ' + xdelimQuote(message) + XDELIM; } -QString CtcpHandler::pack(QString ctcpTag, QString message) { - return XDELIM + ctcpTag + ' ' + message + XDELIM; +void CtcpHandler::query(const QString &bufname, const QString &ctcpTag, const QString &message) { + QList params; + params << serverEncode(bufname) << lowLevelQuote(pack(serverEncode(ctcpTag), userEncode(bufname, message))); + emit putCmd("PRIVMSG", params); } -void CtcpHandler::query(QString bufname, QString ctcpTag, QString message) { - QStringList params; - params << bufname << pack(ctcpTag, message); - emit putCmd("PRIVMSG", params); +void CtcpHandler::reply(const QString &bufname, const QString &ctcpTag, const QString &message) { + QList params; + params << serverEncode(bufname) << lowLevelQuote(pack(serverEncode(ctcpTag), userEncode(bufname, message))); + emit putCmd("NOTICE", params); } -void CtcpHandler::reply(QString bufname, QString ctcpTag, QString message) { - QStringList params; - params << bufname << pack(ctcpTag, message); +void CtcpHandler::packedReply(const QString &bufname, const QList &replies) { + QList params; + + int answerSize = 0; + for(int i = 0; i < replies.count(); i++) { + answerSize += replies.at(i).size(); + } + + QByteArray quotedReply(answerSize, 0); + int nextPos = 0; + QByteArray &reply = quotedReply; + for(int i = 0; i < replies.count(); i++) { + reply = replies.at(i); + quotedReply.replace(nextPos, reply.size(), reply); + nextPos += reply.size(); + } + + params << serverEncode(bufname) << quotedReply; emit putCmd("NOTICE", params); } //******************************/ // CTCP HANDLER //******************************/ -void CtcpHandler::handleAction(CtcpType ctcptype, QString prefix, QString target, QString param) { +void CtcpHandler::handleAction(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &/*reply*/) { Q_UNUSED(ctcptype) emit displayMsg(Message::Action, typeByTarget(target), target, param, prefix); } -void CtcpHandler::handlePing(CtcpType ctcptype, QString prefix, QString target, QString param) { +void CtcpHandler::handleClientinfo(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { Q_UNUSED(target) if(ctcptype == CtcpQuery) { - reply(nickFromMask(prefix), "PING", param); + QStringList supportedHandlers; + foreach(QString handler, providesHandlers()) { + supportedHandlers << handler.toUpper(); + } + reply = supportedHandlers.join(" "); + emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP CLIENTINFO request from %1").arg(prefix)); + } else { + // display clientinfo answer + emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP CLIENTINFO answer from %1: %2") + .arg(nickFromMask(prefix)).arg(param)); + } +} + +void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { + Q_UNUSED(target) + if(ctcptype == CtcpQuery) { + reply = param; emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING request from %1").arg(prefix)); } else { // display ping answer uint now = QDateTime::currentDateTime().toTime_t(); uint then = QDateTime().fromTime_t(param.toInt()).toTime_t(); - emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING answer from %1 with %2 seconds round trip time").arg(prefix).arg(now-then)); + emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP PING answer from %1 with %2 seconds round trip time") + .arg(nickFromMask(prefix)).arg(now-then)); } } -void CtcpHandler::handleVersion(CtcpType ctcptype, QString prefix, QString target, QString param) { +void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { Q_UNUSED(target) if(ctcptype == CtcpQuery) { - // FIXME use real Info about quassel :) - reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC (v%1 build >= %2) -- http://www.quassel-irc.org") - .arg(Global::quasselVersion).arg(Global::quasselBuild)); + reply = QString("Quassel IRC %1 (built on %2) -- http://www.quassel-irc.org").arg(Quassel::buildInfo().plainVersionString).arg(Quassel::buildInfo().buildDate); emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION request by %1").arg(prefix)); } else { // display Version answer - emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION answer from %1: %2").arg(prefix).arg(param)); + emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION answer from %1: %2") + .arg(nickFromMask(prefix)).arg(param)); + } +} + +void CtcpHandler::handleTime(CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { + Q_UNUSED(target) + if(ctcptype == CtcpQuery) { + reply = QDateTime::currentDateTime().toString(); + emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP TIME request by %1").arg(prefix)); + } else { + emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP TIME answer from %1: %2") + .arg(nickFromMask(prefix)).arg(param)); } } -void CtcpHandler::defaultHandler(QString cmd, CtcpType ctcptype, QString prefix, QString target, QString param) { +void CtcpHandler::defaultHandler(const QString &cmd, CtcpType ctcptype, const QString &prefix, const QString &target, const QString ¶m, QString &reply) { Q_UNUSED(ctcptype); Q_UNUSED(target); - Q_UNUSED(param); - emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix)); + Q_UNUSED(reply); + QString str = tr("Received unknown CTCP %1 by %2").arg(cmd).arg(prefix); + if(!param.isEmpty()) + str.append(tr(" with arguments: %1").arg(param)); + emit displayMsg(Message::Error, BufferInfo::StatusBuffer, "", str); } -