From 8c3b7e4773e9f20ad9ea264cbaafaa52485bdf86 Mon Sep 17 00:00:00 2001 From: Manuel Nickschas Date: Fri, 6 Jul 2007 16:48:34 +0000 Subject: [PATCH] Added a function decodeString() to util.{h|cpp} that takes a QByteArray with raw text data and decodes it using a specified text codec. Except the input data is utf8, in which case this function detects utf8 and takes appropriate measures to get a correctly decoded QString regardless of the specified coded. I'd like to use this function for decoding incoming server messages, but we need to change things quite a bit in the Server to do this correctly. See my comment in server.cpp. --- src/CMakeLists.txt | 6 +++--- src/common/util.cpp | 34 ++++++++++++++++++++++++++++++++++ src/common/util.h | 9 +++++++++ src/core/server.cpp | 21 ++++++++++++++++----- src/core/server.h | 2 +- src/qtgui/mainwin.cpp | 4 ++-- 6 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 65a664ba..7e0244ff 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,9 +24,9 @@ IF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_QTGUI) MESSAGE(FATAL_ERROR "\nYou have not selected which parts of Quassel I should build. Aborting.\nRun 'cmake -DBUILD=', where contains one or more of 'core', 'gui' or 'monolithic', or 'all' to build everything.\n") ENDIF(NOT BUILD_MONO AND NOT BUILD_CORE AND NOT BUILD_QTGUI) -IF(BUILD_CORE OR BUILD_QTGUI) - MESSAGE(FATAL_ERROR "\nBuilding of standalone core or GUI not supported at this time. Please check back later.\n") -ENDIF(BUILD_CORE OR BUILD_QTGUI) +#IF(BUILD_CORE OR BUILD_QTGUI) +# MESSAGE(FATAL_ERROR "\nBuilding of standalone core or GUI not supported at this time. Please check back later.\n") +#ENDIF(BUILD_CORE OR BUILD_QTGUI) SET(CMAKE_BUILD_TYPE Debug) diff --git a/src/common/util.cpp b/src/common/util.cpp index 2238cbed..675a735a 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -19,6 +19,8 @@ ***************************************************************************/ #include "util.h" +#include +#include QString nickFromMask(QString mask) { return mask.section('!', 0, 0); @@ -40,6 +42,38 @@ bool isChannelName(QString str) { return QString("#&!+").contains(str[0]); } +QString decodeString(QByteArray input, QString encoding) { + // First, we check if it's utf8. It is very improbable to encounter a string that looks like + // valid utf8, but in fact is not. This means that if the input string passes as valid utf8, it + // is safe to assume that it is. + Q_ASSERT(sizeof(const char) == sizeof(quint8)); // just to make sure + bool isUtf8 = true; + int cnt = 0; + for(int i = 0; i < input.size(); i++) { + if(cnt) { + if((input[i] & 0xc0) != 0x80) { isUtf8 = false; break; } // Following byte does not start with 10 + cnt--; + continue; + } + if(!(input[i] & 0x80)) continue; // 7 bit is ok + if((input[i] & 0xf8) == 0xf0) { cnt = 3; continue; } + if((input[i] & 0xf0) == 0xe0) { cnt = 2; continue; } + if((input[i] & 0xe0) == 0xc0) { cnt = 1; continue; } + isUtf8 = false; break; // 8 bit char, but not utf8! + } + if(isUtf8 && cnt == 0) { + QString s = QString::fromUtf8(input); + qDebug() << "Detected utf8:" << s; + return s; + } + QTextCodec *codec = QTextCodec::codecForName(encoding.toAscii()); + if(!codec) { + qWarning() << QString("Invalid encoding: %1").arg(encoding); + return QString::fromAscii(input); + } + return codec->toUnicode(input); +} + void writeDataToDevice(QIODevice *dev, const QVariant &item) { QByteArray block; QDataStream out(&block, QIODevice::WriteOnly); diff --git a/src/common/util.h b/src/common/util.h index 1a6d889f..067bd76e 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -29,6 +29,15 @@ QString nickFromMask(QString mask); QString userFromMask(QString mask); QString hostFromMask(QString mask); +//! Take a string and decode it using the specified text codec, recognizing utf8. +/** This function takes a string and first checks if it is encoded in utf8, in which case it is + * decoded appropriately. Otherwise, the specified text codec is used to transform the string. + * \param input The input string containing encoded data + * \param encoding The text encoding we assume if it's not utf8 + * \return The decoded string. + */ +QString decodeString(QByteArray input, QString encoding = "ISO-8859-15"); + bool isChannelName(QString str); /** diff --git a/src/core/server.cpp b/src/core/server.cpp index 39fcfb34..92fe8049 100644 --- a/src/core/server.cpp +++ b/src/core/server.cpp @@ -82,9 +82,9 @@ void Server::disconnectFromIrc(QString net) { void Server::socketHasData() { while(socket.canReadLine()) { - QString s = socket.readLine().trimmed(); + QByteArray s = socket.readLine().trimmed(); //qDebug() << "Read" << s; - emit recvRawServerMsg(s); + //emit recvRawServerMsg(s); // signal not needed, and we should make sure we consider encodings where we need them //Message *msg = Message::createFromServerString(this, s); handleServerMsg(s); } @@ -158,13 +158,24 @@ void Server::putCmd(QString cmd, QStringList params, QString prefix) { socket.write(m.toAscii()); } -/** Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */ -void Server::handleServerMsg(QString msg) { +/*! Handle a raw message string sent by the server. We try to find a suitable handler, otherwise we call a default handler. */ +void Server::handleServerMsg(QByteArray rawmsg) { try { - if(msg.isEmpty()) { + if(rawmsg.isEmpty()) { qWarning() << "Received empty string from server!"; return; } + // TODO Implement encoding conversion + /* At this point, we have a raw message as a byte array. This needs to be converted to a QString somewhere. + * Problem is, that at this point we don't know which encoding to use for the various parts of the message. + * This is something the command handler needs to take care of (e.g. PRIVMSG needs to first parse for CTCP, + * and then convert the raw strings into the correct encoding. + * We _can_ safely assume Server encoding for prefix and cmd, but not for the params. Therefore, we need to + * change from a QStringList to a QList in all the handlers, and have the handlers call decodeString + * where needed... + */ + QString msg = QString::fromLatin1(rawmsg); + // OK, first we split the raw message into its various parts... QString prefix = ""; QString cmd; diff --git a/src/core/server.h b/src/core/server.h index 34a45142..0f9a1d74 100644 --- a/src/core/server.h +++ b/src/core/server.h @@ -159,7 +159,7 @@ class Server : public QThread { QHash topics; // stores topics for each buffer VarMap serverSupports; // stores results from RPL_ISUPPORT - void handleServerMsg(QString rawMsg); + void handleServerMsg(QByteArray rawMsg); void handleUserInput(QString buffer, QString usrMsg); // CTCP Stuff diff --git a/src/qtgui/mainwin.cpp b/src/qtgui/mainwin.cpp index fedf028c..6b89e20e 100644 --- a/src/qtgui/mainwin.cpp +++ b/src/qtgui/mainwin.cpp @@ -31,8 +31,8 @@ MainWin::MainWin(QtGui *_gui, QWidget *parent) : QMainWindow(parent), gui(_gui) { ui.setupUi(this); - setWindowTitle("Quassel IRC"); - //setWindowTitle("Κυασελ Εγαρζη"); + //setWindowTitle("Quassel IRC"); + setWindowTitle(QString::fromUtf8("Κυασελ Εγαρζη")); setWindowIcon(QIcon(":/qirc-icon.png")); setWindowIconText("Quassel IRC"); -- 2.20.1