Note to myself: QByteArray("\000") != QByteArray (1, '\000')
[quassel.git] / src / core / ctcphandler.cpp
index 23753cc..b7fe6c9 100644 (file)
@@ -30,9 +30,9 @@ CtcpHandler::CtcpHandler(NetworkConnection *parent)
 {
 
   QByteArray MQUOTE = QByteArray("\020");
-  ctcpMDequoteHash[MQUOTE + '0'] = QByteArray("\000");
-  ctcpMDequoteHash[MQUOTE + 'n'] = QByteArray("\n");
-  ctcpMDequoteHash[MQUOTE + 'r'] = QByteArray("\r");
+  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");
@@ -40,7 +40,23 @@ CtcpHandler::CtcpHandler(NetworkConnection *parent)
   ctcpXDelimDequoteHash[XQUOTE + QByteArray("a")] = XDELIM;
 }
 
-QByteArray CtcpHandler::dequote(const QByteArray &message) {
+QByteArray CtcpHandler::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 CtcpHandler::lowLevelDequote(const QByteArray &message) {
   QByteArray dequotedMessage;
   QByteArray messagepart;
   QHash<QByteArray, QByteArray>::iterator ctcpquote;
@@ -62,6 +78,15 @@ QByteArray CtcpHandler::dequote(const QByteArray &message) {
   return dequotedMessage;
 }
 
+QByteArray CtcpHandler::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 CtcpHandler::xdelimDequote(const QByteArray &message) {
   QByteArray dequotedMessage;
@@ -88,13 +113,13 @@ void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const
   QByteArray ctcp;
   
   //lowlevel message dequote
-  QByteArray dequotedMessage = dequote(message);
+  QByteArray dequotedMessage = lowLevelDequote(message);
 
   CtcpType ctcptype = messageType == Message::Notice
     ? CtcpReply
     : CtcpQuery;
   
-  quint8 flags = (messageType == Message::Notice && !network()->isChannelName(target))
+  Message::Flags flags = (messageType == Message::Notice && !network()->isChannelName(target))
     ? Message::Redirected
     : Message::None;
 
@@ -108,13 +133,11 @@ void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const
 
     xdelimEndPos = dequotedMessage.indexOf(XDELIM, xdelimPos + 1);
     if(xdelimEndPos == -1) {
-      // no matching end delimiter found...
-      dequotedMessage = dequotedMessage.mid(xdelimPos + 1);
-      break;
-    } else {
-      ctcp = xdelimDequote(dequotedMessage.mid(xdelimPos + 1, xdelimEndPos - xdelimPos - 1));
-      dequotedMessage = dequotedMessage.mid(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 = userDecode(target, ctcp.left(spacePos));
@@ -137,19 +160,18 @@ void CtcpHandler::parse(Message::Type messageType, const QString &prefix, const
 }
 
 QByteArray CtcpHandler::pack(const QByteArray &ctcpTag, const QByteArray &message) {
-  return XDELIM + ctcpTag + ' ' + message + XDELIM;
+  return XDELIM + ctcpTag + ' ' + xdelimQuote(message) + XDELIM;
 }
 
-// TODO handle encodings correctly!
 void CtcpHandler::query(const QString &bufname, const QString &ctcpTag, const QString &message) {
   QList<QByteArray> params;
-  params << serverEncode(bufname) << pack(serverEncode(ctcpTag), userEncode(bufname, message));
+  params << serverEncode(bufname) << lowLevelQuote(pack(serverEncode(ctcpTag), userEncode(bufname, message)));
   emit putCmd("PRIVMSG", params);
 }
 
 void CtcpHandler::reply(const QString &bufname, const QString &ctcpTag, const QString &message) {
   QList<QByteArray> params;
-  params << serverEncode(bufname) << pack(serverEncode(ctcpTag), userEncode(bufname, message));
+  params << serverEncode(bufname) << lowLevelQuote(pack(serverEncode(ctcpTag), userEncode(bufname, message)));
   emit putCmd("NOTICE", params);
 }
 
@@ -177,8 +199,8 @@ void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QSt
 void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param) {
   Q_UNUSED(target)
   if(ctcptype == CtcpQuery) {
-    reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC (v%1 build >= %2) -- http://www.quassel-irc.org")
-        .arg(Global::quasselVersion).arg(Global::quasselBuild));
+    reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC %1 (built on %2) -- http://www.quassel-irc.org")
+        .arg(Global::quasselVersion).arg(Global::quasselBuildDate));
     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION request by %1").arg(prefix));
   } else {
     // display Version answer