Introduce CtcpParser for CTCP-related event processing
authorManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Oct 2010 18:45:07 +0000 (20:45 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Oct 2010 21:48:53 +0000 (23:48 +0200)
Functionality from CtcpHandler has been ported over to CtcpParser to process
IrcEventRawMessage events and generate appropriate MessageEvents and CtcpEvents from the
raw input of PRIVMSG and NOTICE.

CtcpEvents are not handled/stringified yet.

src/common/CMakeLists.txt
src/common/ctcpevent.cpp [new file with mode: 0644]
src/common/ctcpevent.h [new file with mode: 0644]
src/common/eventmanager.h
src/core/CMakeLists.txt
src/core/coresession.cpp
src/core/coresession.h
src/core/ctcpparser.cpp [new file with mode: 0644]
src/core/ctcpparser.h [new file with mode: 0644]
src/core/ircparser.cpp

index eb48554..e36aeaa 100644 (file)
@@ -12,6 +12,7 @@ set(SOURCES
     bufferviewconfig.cpp
     bufferviewmanager.cpp
     cliparser.cpp
+    ctcpevent.cpp
     event.cpp
     eventmanager.cpp
     identity.cpp
@@ -56,6 +57,7 @@ set(HEADERS ${MOC_HDRS}
     abstractcliparser.h
     bufferinfo.h
     cliparser.h
+    ctcpevent.h
     event.h
     ircevent.h
     networkevent.h
diff --git a/src/common/ctcpevent.cpp b/src/common/ctcpevent.cpp
new file mode 100644 (file)
index 0000000..7a8dce8
--- /dev/null
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#include "ctcpevent.h"
diff --git a/src/common/ctcpevent.h b/src/common/ctcpevent.h
new file mode 100644 (file)
index 0000000..08eac20
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#ifndef CTCPEVENT_H
+#define CTCPEVENT_H
+
+#include "ircevent.h"
+
+#include <QUuid>
+
+class CtcpEvent : public IrcEvent {
+
+public:
+  enum CtcpType {
+    Query,
+    Reply
+  };
+
+  explicit CtcpEvent(EventManager::EventType type, Network *network, const QString &prefix, const QString &target,
+                     CtcpType ctcpType, const QString &ctcpCmd, const QString &param,
+                     const QDateTime &timestamp = QDateTime(), const QUuid &uuid = QUuid())
+    : IrcEvent(type, network, prefix),
+    _ctcpType(ctcpType),
+    _ctcpCmd(ctcpCmd),
+    _target(target),
+    _param(param),
+    _uuid(uuid)
+  {
+    setTimestamp(timestamp);
+  }
+
+  inline CtcpType ctcpType() const { return _ctcpType; }
+  inline void setCtcpType(CtcpType type) { _ctcpType = type; }
+
+  inline QString ctcpCmd() const { return _ctcpCmd; }
+  inline void setCtcpCmd(const QString &ctcpCmd) { _ctcpCmd = ctcpCmd; }
+
+  inline QString target() const { return _target; }
+  inline void setTarget(const QString &target) { _target = target; }
+
+  inline QString param() const { return _param; }
+  inline void setParam(const QString &param) { _param = param; }
+
+  inline QString reply() const { return _reply; }
+  inline void setReply(const QString &reply) { _reply = reply; }
+
+  inline QUuid uuid() const { return _uuid; }
+  inline void setUuid(const QUuid &uuid) { _uuid = uuid; }
+
+protected:
+  virtual inline QString className() const { return "CtcpEvent"; }
+  virtual inline void debugInfo(QDebug &dbg) const {
+    NetworkEvent::debugInfo(dbg);
+    dbg << ", prefix = " << qPrintable(prefix())
+        << ", target = " << qPrintable(target())
+        << ", ctcptype = " << (ctcpType() == Query? "query" : "reply")
+        << ", cmd = " << qPrintable(ctcpCmd())
+        << ", param = " << qPrintable(param())
+        << ", reply = " << qPrintable(reply());
+  }
+
+private:
+  CtcpType _ctcpType;
+  QString _ctcpCmd;
+  QString _target, _param, _reply;
+  QUuid _uuid;
+};
+
+#endif
index bc0a1d4..025493b 100644 (file)
@@ -46,13 +46,14 @@ public:
   };
 
   enum EventFlag {
+    Self     = 0x01, ///< Self-generated (user input) event
     Fake     = 0x08, ///< Ignore this in CoreSessionEventProcessor
     Netsplit = 0x10, ///< Netsplit join/part, ignore on display
     Backlog  = 0x20,
     Silent   = 0x40, ///< Don't generate a MessageEvent
     Stopped  = 0x80
   };
-  Q_DECLARE_FLAGS(EventFlags, EventFlag)
+  Q_DECLARE_FLAGS(EventFlags, EventFlag);
 
   /*
 
@@ -104,6 +105,9 @@ public:
     IrcEventNumericMask         = 0x00000fff, /* for checking if an event is numeric */
 
     MessageEvent                = 0x00040000, ///< Stringified event suitable for converting to Message
+
+    CtcpEvent                   = 0x00050000,
+    CtcpEventFlush,
   };
 
   EventManager(QObject *parent = 0);
@@ -111,6 +115,7 @@ public:
 
   EventType eventTypeByName(const QString &name) const;
   EventType eventGroupByName(const QString &name) const;
+
   QString enumName(EventType type) const;
 
 public slots:
index de1b6fb..fe99f34 100644 (file)
@@ -30,6 +30,7 @@ set(SOURCES
     coreuserinputhandler.cpp
     coreusersettings.cpp
     ctcphandler.cpp
+    ctcpparser.cpp
     eventstringifier.cpp
     ircparser.cpp
     ircserverhandler.cpp
@@ -61,6 +62,7 @@ set(MOC_HDRS
     coresessioneventprocessor.h
     coreuserinputhandler.h
     ctcphandler.h
+    ctcpparser.h
     eventstringifier.h
     ircparser.h
     ircserverhandler.h
index 504fdab..3fd539e 100644 (file)
@@ -34,6 +34,7 @@
 #include "corenetworkconfig.h"
 #include "coresessioneventprocessor.h"
 #include "coreusersettings.h"
+#include "ctcpparser.h"
 #include "eventmanager.h"
 #include "eventstringifier.h"
 #include "ircchannel.h"
@@ -63,7 +64,8 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
     _coreInfo(this),
     _eventManager(new EventManager(this)),
     _eventStringifier(new EventStringifier(this)),
-    _eventProcessor(new CoreSessionEventProcessor(this)),
+    _sessionEventProcessor(new CoreSessionEventProcessor(this)),
+    _ctcpParser(new CtcpParser(this)),
     _ircParser(new IrcParser(this)),
     scriptEngine(new QScriptEngine(this)),
     _processMessages(false),
@@ -96,11 +98,13 @@ CoreSession::CoreSession(UserId uid, bool restoreState, QObject *parent)
   initScriptEngine();
 
   eventManager()->registerObject(ircParser(), EventManager::NormalPriority);
-  eventManager()->registerObject(eventProcessor(), EventManager::HighPriority); // needs to process events *before* the stringifier!
+  eventManager()->registerObject(sessionEventProcessor(), EventManager::HighPriority); // needs to process events *before* the stringifier!
+  eventManager()->registerObject(ctcpParser(), EventManager::NormalPriority);
   eventManager()->registerObject(eventStringifier(), EventManager::NormalPriority);
   eventManager()->registerObject(this, EventManager::LowPriority); // for sending MessageEvents to the client
    // some events need to be handled after msg generation
-  eventManager()->registerObject(eventProcessor(), EventManager::LowPriority, "lateProcess");
+  eventManager()->registerObject(sessionEventProcessor(), EventManager::LowPriority, "lateProcess");
+  eventManager()->registerObject(ctcpParser(), EventManager::LowPriority, "send");
 
   // periodically save our session state
   connect(&(Core::instance()->syncTimer()), SIGNAL(timeout()), this, SLOT(saveSessionState()));
index 25bf012..3dd77f3 100644 (file)
@@ -38,6 +38,7 @@ class CoreIrcListHelper;
 class CoreNetwork;
 class CoreNetworkConfig;
 class CoreSessionEventProcessor;
+class CtcpParser;
 class EventManager;
 class EventStringifier;
 class IrcParser;
@@ -72,7 +73,8 @@ public:
 
   inline EventManager *eventManager() const { return _eventManager; }
   inline EventStringifier *eventStringifier() const { return _eventStringifier; }
-  inline CoreSessionEventProcessor *eventProcessor() const { return _eventProcessor; }
+  inline CoreSessionEventProcessor *sessionEventProcessor() const { return _sessionEventProcessor; }
+  inline CtcpParser *ctcpParser() const { return _ctcpParser; }
   inline IrcParser *ircParser() const { return _ircParser; }
 
   inline CoreIrcListHelper *ircListHelper() const { return _ircListHelper; }
@@ -194,7 +196,8 @@ private:
 
   EventManager *_eventManager;
   EventStringifier *_eventStringifier; // should eventually move into client
-  CoreSessionEventProcessor *_eventProcessor;
+  CoreSessionEventProcessor *_sessionEventProcessor;
+  CtcpParser *_ctcpParser;
   IrcParser *_ircParser;
 
   QScriptEngine *scriptEngine;
diff --git a/src/core/ctcpparser.cpp b/src/core/ctcpparser.cpp
new file mode 100644 (file)
index 0000000..fc71057
--- /dev/null
@@ -0,0 +1,260 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#include "ctcpparser.h"
+
+#include "coresession.h"
+#include "ctcpevent.h"
+#include "messageevent.h"
+
+const QByteArray XDELIM = "\001";
+
+CtcpParser::CtcpParser(CoreSession *coreSession, 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;
+}
+
+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;
+
+  MessageEvent *msgEvent = new MessageEvent(msgType, event->network(), msg, sender, target, msgFlags);
+  msgEvent->setTimestamp(event->timestamp());
+
+  coreSession()->eventManager()->sendEvent(msgEvent);
+}
+
+QByteArray CtcpParser::lowLevelQuote(const QByteArray &message) {
+  QByteArray quotedMessage = message;
+
+  QHash<QByteArray, QByteArray> quoteHash = _ctcpMDequoteHash;
+  QByteArray MQUOTE = QByteArray("\020");
+  quoteHash.remove(MQUOTE + MQUOTE);
+  quotedMessage.replace(MQUOTE, MQUOTE + MQUOTE);
+
+  QHash<QByteArray, QByteArray>::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<QByteArray, QByteArray>::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;
+  }
+  return dequotedMessage;
+}
+
+QByteArray CtcpParser::xdelimQuote(const QByteArray &message) {
+  QByteArray quotedMessage = message;
+  QHash<QByteArray, QByteArray>::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<QByteArray, QByteArray>::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;
+  }
+  return dequotedMessage;
+}
+
+void CtcpParser::processIrcEventRawNotice(IrcEventRawMessage *event) {
+  parse(event, Message::Notice);
+}
+
+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());
+
+  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<CtcpEvent *> 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);
+
+    //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();
+    }
+
+    ctcpcmd = ctcpcmd.toUpper();
+
+    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;
+    }
+  }
+  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);
+    }
+  }
+
+  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;
+
+  return XDELIM + ctcpTag + ' ' + xdelimQuote(message) + XDELIM;
+}
+
+void CtcpParser::query(CoreNetwork *net, const QString &bufname, const QString &ctcpTag, const QString &message) {
+  QList<QByteArray> 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<QByteArray> 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<QByteArray> &replies) {
+  QList<QByteArray> 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);
+}
diff --git a/src/core/ctcpparser.h b/src/core/ctcpparser.h
new file mode 100644 (file)
index 0000000..1091596
--- /dev/null
@@ -0,0 +1,91 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2010 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   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.             *
+ ***************************************************************************/
+
+#ifndef CTCPPARSER_H
+#define CTCPPARSER_H
+
+#include <QUuid>
+
+#include "corenetwork.h"
+#include "eventmanager.h"
+#include "ircevent.h"
+
+class CoreSession;
+class CtcpEvent;
+
+class CtcpParser : public QObject {
+  Q_OBJECT
+
+public:
+  CtcpParser(CoreSession *coreSession, QObject *parent = 0);
+
+  inline CoreSession *coreSession() const { return _coreSession; }
+
+  void query(CoreNetwork *network, const QString &bufname, const QString &ctcpTag, const QString &message);
+  void reply(CoreNetwork *network, const QString &bufname, const QString &ctcpTag, const QString &message);
+
+  Q_INVOKABLE void processIrcEventRawNotice(IrcEventRawMessage *event);
+  Q_INVOKABLE void processIrcEventRawPrivmsg(IrcEventRawMessage *event);
+
+  Q_INVOKABLE void sendCtcpEvent(CtcpEvent *event);
+
+protected:
+  inline CoreNetwork *coreNetwork(NetworkEvent *e) const { return qobject_cast<CoreNetwork *>(e->network()); }
+
+  // FIXME duplicates functionality in EventStringifier, maybe want to put that in something common
+  //! Creates and sends a MessageEvent
+  void displayMsg(NetworkEvent *event,
+                  Message::Type msgType,
+                  const QString &msg,
+                  const QString &sender = QString(),
+                  const QString &target = QString(),
+                  Message::Flags msgFlags = Message::None);
+
+  void parse(IrcEventRawMessage *event, Message::Type msgType);
+
+  QByteArray lowLevelQuote(const QByteArray &);
+  QByteArray lowLevelDequote(const QByteArray &);
+  QByteArray xdelimQuote(const QByteArray &);
+  QByteArray xdelimDequote(const QByteArray &);
+
+  QByteArray pack(const QByteArray &ctcpTag, const QByteArray &message);
+  void packedReply(CoreNetwork *network, const QString &bufname, const QList<QByteArray> &replies);
+
+private:
+  inline QString targetDecode(IrcEventRawMessage *e, const QByteArray &msg) { return coreNetwork(e)->userDecode(e->target(), msg); }
+
+  CoreSession *_coreSession;
+
+  struct CtcpReply {
+    CoreNetwork *network;
+    QString bufferName;
+    QList<QByteArray> replies;
+
+    CtcpReply() : network(0) {}
+    CtcpReply(CoreNetwork *net, const QString &buf) : network(net), bufferName(buf) {}
+  };
+
+  QHash<QUuid, CtcpReply> _replies;
+
+  QHash<QByteArray, QByteArray> _ctcpMDequoteHash;
+  QHash<QByteArray, QByteArray> _ctcpXDelimDequoteHash;
+};
+
+#endif
index 2a06811..260e80b 100644 (file)
@@ -175,7 +175,6 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) {
         msg = decrypt(net, target, msg);
 
         events << new IrcEventRawMessage(EventManager::IrcEventRawPrivmsg, net, msg, prefix, target, e->timestamp());
-        //events << new MessageEvent(Message::Plain, net, net->channelDecode(target, msg), target, prefix);
       }
     }
     break;