X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcore%2Fctcpparser.cpp;h=1f1660fc45f5a5267ff0b5518fdaf34e31d61478;hp=fc710573ecda1d186b31a1b9785bf457273b4ac9;hb=5b686746c880e5cda6d5de3e08180ea4332ff222;hpb=283fdb2c49e5efa1d497d8c3e6f624f86d008ff8 diff --git a/src/core/ctcpparser.cpp b/src/core/ctcpparser.cpp index fc710573..1f1660fc 100644 --- a/src/core/ctcpparser.cpp +++ b/src/core/ctcpparser.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2010 by the Quassel Project * + * Copyright (C) 2005-2012 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "ctcpparser.h" @@ -27,234 +27,264 @@ const QByteArray XDELIM = "\001"; CtcpParser::CtcpParser(CoreSession *coreSession, QObject *parent) - : QObject(parent), + : QObject(parent), _coreSession(coreSession) { - 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; - - QByteArray XQUOTE = QByteArray("\134"); - _ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE; - _ctcpXDelimDequoteHash[XQUOTE + QByteArray("a")] = XDELIM; + 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; + + QByteArray XQUOTE = QByteArray("\134"); + _ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE; + _ctcpXDelimDequoteHash[XQUOTE + QByteArray("a")] = XDELIM; + + connect(this, SIGNAL(newEvent(Event *)), _coreSession->eventManager(), SLOT(postEvent(Event *))); } + void CtcpParser::displayMsg(NetworkEvent *event, Message::Type msgType, const QString &msg, const QString &sender, - const QString &target, Message::Flags msgFlags) { - if(event->testFlag(EventManager::Silent)) - return; + const QString &target, Message::Flags msgFlags) +{ + if (event->testFlag(EventManager::Silent)) + return; - MessageEvent *msgEvent = new MessageEvent(msgType, event->network(), msg, sender, target, msgFlags); - msgEvent->setTimestamp(event->timestamp()); + MessageEvent *msgEvent = new MessageEvent(msgType, event->network(), msg, sender, target, msgFlags); + msgEvent->setTimestamp(event->timestamp()); - coreSession()->eventManager()->sendEvent(msgEvent); + emit newEvent(msgEvent); } -QByteArray CtcpParser::lowLevelQuote(const QByteArray &message) { - QByteArray quotedMessage = message; - QHash quoteHash = _ctcpMDequoteHash; - QByteArray MQUOTE = QByteArray("\020"); - quoteHash.remove(MQUOTE + MQUOTE); - quotedMessage.replace(MQUOTE, MQUOTE + MQUOTE); +QByteArray CtcpParser::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; + QHash::const_iterator quoteIter = quoteHash.constBegin(); + while (quoteIter != quoteHash.constEnd()) { + quotedMessage.replace(quoteIter.value(), quoteIter.key()); + quoteIter++; + } + return quotedMessage; } -QByteArray CtcpParser::lowLevelDequote(const QByteArray &message) { - QByteArray dequotedMessage; - QByteArray messagepart; - QHash::iterator ctcpquote; - - // copy dequote Message - for(int i = 0; i < message.size(); 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()) { - messagepart = ctcpquote.value(); - ++i; - break; + +QByteArray CtcpParser::lowLevelDequote(const QByteArray &message) +{ + QByteArray dequotedMessage; + QByteArray messagepart; + QHash::iterator ctcpquote; + + // copy dequote Message + for (int i = 0; i < message.size(); 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()) { + messagepart = ctcpquote.value(); + ++i; + break; + } + } } - } + dequotedMessage += messagepart; } - dequotedMessage += messagepart; - } - return dequotedMessage; + return dequotedMessage; } -QByteArray CtcpParser::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; + +QByteArray CtcpParser::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; } -QByteArray CtcpParser::xdelimDequote(const QByteArray &message) { - QByteArray dequotedMessage; - QByteArray messagepart; - QHash::iterator xdelimquote; - - for(int i = 0; i < message.size(); 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()) { - messagepart = xdelimquote.value(); - i++; - break; + +QByteArray CtcpParser::xdelimDequote(const QByteArray &message) +{ + QByteArray dequotedMessage; + QByteArray messagepart; + QHash::iterator xdelimquote; + + for (int i = 0; i < message.size(); 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()) { + messagepart = xdelimquote.value(); + i++; + break; + } + } } - } + dequotedMessage += messagepart; } - dequotedMessage += messagepart; - } - return dequotedMessage; + return dequotedMessage; } -void CtcpParser::processIrcEventRawNotice(IrcEventRawMessage *event) { - parse(event, Message::Notice); + +void CtcpParser::processIrcEventRawNotice(IrcEventRawMessage *event) +{ + parse(event, Message::Notice); } -void CtcpParser::processIrcEventRawPrivmsg(IrcEventRawMessage *event) { - parse(event, Message::Plain); + +void CtcpParser::processIrcEventRawPrivmsg(IrcEventRawMessage *event) +{ + parse(event, Message::Plain); } -void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype) { - QByteArray ctcp; - //lowlevel message dequote - QByteArray dequotedMessage = lowLevelDequote(e->rawMessage()); +void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype) +{ + QByteArray ctcp; + + //lowlevel message dequote + QByteArray dequotedMessage = lowLevelDequote(e->rawMessage()); + + CtcpEvent::CtcpType ctcptype = e->type() == EventManager::IrcEventRawNotice + ? CtcpEvent::Reply + : CtcpEvent::Query; + + Message::Flags flags = (ctcptype == CtcpEvent::Reply && !e->network()->isChannelName(e->target())) + ? Message::Redirected + : Message::None; + + QList ctcpEvents; + QUuid uuid; // needed to group all replies together + + // extract tagged / extended data + int xdelimPos = -1; + int xdelimEndPos = -1; + int spacePos = -1; + while ((xdelimPos = dequotedMessage.indexOf(XDELIM)) != -1) { + if (xdelimPos > 0) + displayMsg(e, messagetype, targetDecode(e, dequotedMessage.left(xdelimPos)), e->prefix(), e->target(), 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); - CtcpEvent::CtcpType ctcptype = e->type() == EventManager::IrcEventRawNotice - ? CtcpEvent::Reply - : CtcpEvent::Query; + //dispatch the ctcp command + QString ctcpcmd = targetDecode(e, ctcp.left(spacePos)); + QString ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1)); - Message::Flags flags = (ctcptype == CtcpEvent::Reply && !e->network()->isChannelName(e->target())) - ? Message::Redirected - : Message::None; + spacePos = ctcp.indexOf(' '); + if (spacePos != -1) { + ctcpcmd = targetDecode(e, ctcp.left(spacePos)); + ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1)); + } + else { + ctcpcmd = targetDecode(e, ctcp); + ctcpparam = QString(); + } - QList ctcpEvents; - QUuid uuid; // needed to group all replies together + ctcpcmd = ctcpcmd.toUpper(); - // extract tagged / extended data - int xdelimPos = -1; - int xdelimEndPos = -1; - int spacePos = -1; - while((xdelimPos = dequotedMessage.indexOf(XDELIM)) != -1) { - if(xdelimPos > 0) - displayMsg(e, messagetype, targetDecode(e, dequotedMessage.left(xdelimPos)), e->prefix(), e->target(), flags); + // we don't want to block /me messages by the CTCP ignore list + if (ctcpcmd == QLatin1String("ACTION") || !coreSession()->ignoreListManager()->ctcpMatch(e->prefix(), e->network()->networkName(), ctcpcmd)) { + if (uuid.isNull()) + uuid = QUuid::createUuid(); - xdelimEndPos = dequotedMessage.indexOf(XDELIM, xdelimPos + 1); - if(xdelimEndPos == -1) { - // no matching end delimiter found... treat rest of the message as ctcp - xdelimEndPos = dequotedMessage.count(); + CtcpEvent *event = new CtcpEvent(EventManager::CtcpEvent, e->network(), e->prefix(), e->target(), + ctcptype, ctcpcmd, ctcpparam, e->timestamp(), uuid); + ctcpEvents << event; + } } - ctcp = xdelimDequote(dequotedMessage.mid(xdelimPos + 1, xdelimEndPos - xdelimPos - 1)); - dequotedMessage = dequotedMessage.mid(xdelimEndPos + 1); - - //dispatch the ctcp command - QString ctcpcmd = targetDecode(e, ctcp.left(spacePos)); - QString ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1)); - - spacePos = ctcp.indexOf(' '); - if(spacePos != -1) { - ctcpcmd = targetDecode(e, ctcp.left(spacePos)); - ctcpparam = targetDecode(e, ctcp.mid(spacePos + 1)); - } else { - ctcpcmd = targetDecode(e, ctcp); - ctcpparam = QString(); + if (!ctcpEvents.isEmpty()) { + _replies.insert(uuid, CtcpReply(coreNetwork(e), nickFromMask(e->prefix()))); + CtcpEvent *flushEvent = new CtcpEvent(EventManager::CtcpEventFlush, e->network(), e->prefix(), e->target(), + ctcptype, "INVALID", QString(), e->timestamp(), uuid); + ctcpEvents << flushEvent; + foreach(CtcpEvent *event, ctcpEvents) { + emit newEvent(event); + } } - ctcpcmd = ctcpcmd.toUpper(); + if (!dequotedMessage.isEmpty()) + displayMsg(e, messagetype, targetDecode(e, dequotedMessage), e->prefix(), e->target(), flags); +} - if(!coreSession()->ignoreListManager()->ctcpMatch(e->prefix(), e->network()->networkName(), ctcpcmd)) { - if(uuid.isNull()) - uuid = QUuid::createUuid(); - CtcpEvent *event = new CtcpEvent(EventManager::CtcpEvent, e->network(), e->prefix(), e->target(), - ctcptype, ctcpcmd, ctcpparam, e->timestamp(), uuid); - ctcpEvents << event; +void CtcpParser::sendCtcpEvent(CtcpEvent *e) +{ + CoreNetwork *net = coreNetwork(e); + if (e->type() == EventManager::CtcpEvent) { + QByteArray quotedReply; + QString bufname = nickFromMask(e->prefix()); + if (e->ctcpType() == CtcpEvent::Query && !e->reply().isNull()) { + if (_replies.contains(e->uuid())) + _replies[e->uuid()].replies << lowLevelQuote(pack(net->serverEncode(e->ctcpCmd()), + net->userEncode(bufname, e->reply()))); + else + // reply not caused by a request processed in here, so send it off immediately + reply(net, bufname, e->ctcpCmd(), e->reply()); + } } - } - if(!ctcpEvents.isEmpty()) { - _replies.insert(uuid, CtcpReply(coreNetwork(e), nickFromMask(e->prefix()))); - CtcpEvent *flushEvent = new CtcpEvent(uuid); - ctcpEvents << flushEvent; - foreach(CtcpEvent *event, ctcpEvents) { - coreSession()->eventManager()->sendEvent(event); + else if (e->type() == EventManager::CtcpEventFlush && _replies.contains(e->uuid())) { + CtcpReply reply = _replies.take(e->uuid()); + if (reply.replies.count()) + packedReply(net, reply.bufferName, reply.replies); } - } - - if(!dequotedMessage.isEmpty()) - displayMsg(e, messagetype, targetDecode(e, dequotedMessage), e->prefix(), e->target(), flags); } -void CtcpParser::sendCtcpEvent(CtcpEvent *e) { - CoreNetwork *net = coreNetwork(e); - if(e->type() == EventManager::CtcpEvent) { - QByteArray quotedReply; - QString bufname = nickFromMask(e->prefix()); - if(e->ctcpType() == CtcpEvent::Query && !e->reply().isNull()) { - if(_replies.contains(e->uuid())) - _replies[e->uuid()].replies << lowLevelQuote(pack(net->serverEncode(e->ctcpCmd()), - net->userEncode(bufname, e->reply()))); - else - // reply not caused by a request processed in here, so send it off immediately - reply(net, bufname, e->ctcpCmd(), e->reply()); - } - } else if(e->type() == EventManager::CtcpEventFlush && _replies.contains(e->uuid())) { - CtcpReply reply = _replies.take(e->uuid()); - packedReply(net, reply.bufferName, reply.replies); - } -} -QByteArray CtcpParser::pack(const QByteArray &ctcpTag, const QByteArray &message) { - if(message.isEmpty()) - return XDELIM + ctcpTag + XDELIM; +QByteArray CtcpParser::pack(const QByteArray &ctcpTag, const QByteArray &message) +{ + if (message.isEmpty()) + return XDELIM + ctcpTag + XDELIM; - return XDELIM + ctcpTag + ' ' + xdelimQuote(message) + XDELIM; + return XDELIM + ctcpTag + ' ' + xdelimQuote(message) + XDELIM; } -void CtcpParser::query(CoreNetwork *net, const QString &bufname, const QString &ctcpTag, const QString &message) { - QList params; - params << net->serverEncode(bufname) << lowLevelQuote(pack(net->serverEncode(ctcpTag), net->userEncode(bufname, message))); - net->putCmd("PRIVMSG", params); + +void CtcpParser::query(CoreNetwork *net, const QString &bufname, const QString &ctcpTag, const QString &message) +{ + QList params; + params << net->serverEncode(bufname) << lowLevelQuote(pack(net->serverEncode(ctcpTag), net->userEncode(bufname, message))); + net->putCmd("PRIVMSG", params); } -void CtcpParser::reply(CoreNetwork *net, const QString &bufname, const QString &ctcpTag, const QString &message) { - QList params; - params << net->serverEncode(bufname) << lowLevelQuote(pack(net->serverEncode(ctcpTag), net->userEncode(bufname, message))); - net->putCmd("NOTICE", params); + +void CtcpParser::reply(CoreNetwork *net, const QString &bufname, const QString &ctcpTag, const QString &message) +{ + QList params; + params << net->serverEncode(bufname) << lowLevelQuote(pack(net->serverEncode(ctcpTag), net->userEncode(bufname, message))); + net->putCmd("NOTICE", params); } -void CtcpParser::packedReply(CoreNetwork *net, 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 << net->serverEncode(bufname) << quotedReply; - // FIXME user proper event - net->putCmd("NOTICE", params); + +void CtcpParser::packedReply(CoreNetwork *net, 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; + quotedReply.reserve(answerSize); + for (int i = 0; i < replies.count(); i++) { + quotedReply.append(replies.at(i)); + } + + params << net->serverEncode(bufname) << quotedReply; + // FIXME user proper event + net->putCmd("NOTICE", params); }