From: Manuel Nickschas Date: Tue, 19 Feb 2013 22:34:28 +0000 (-0800) Subject: Merge pull request #7 from Tucos/bug-640 X-Git-Tag: 0.9-beta1~15 X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=commitdiff_plain;h=4c80eeb2d07b5ca75fd399b51c939961fdff1670;hp=68ee619cbd98ba95c12efb12a7d32d5ca567b40e Merge pull request #7 from Tucos/bug-640 Add codec blacklist for UTF-8 detection --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 1bd917c9..353511d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,9 +30,8 @@ project(QuasselIRC) include(CheckFunctionExists) include(CheckIncludeFile) -# cmake 2.6.2 is required for KDE >=4.2 and should be widespread enough now # For building against Qt5, we check for an even newer cmake version below! -cmake_minimum_required(VERSION 2.6.2 FATAL_ERROR) +cmake_minimum_required(VERSION 2.8.1 FATAL_ERROR) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) @@ -69,6 +68,7 @@ option(STATIC "Enable static building (might not be portable)" OFF) if(APPLE) option(DEPLOY "Mac OS X only! Adds required libs to bundle resources and create a dmg. Note: requires Qt to be built with 10.4u SDK" OFF) + option(WITH_NOTIFICATION_CENTER "Enable OS X Notification Center support" ON) endif(APPLE) # Default to embedding data in the static case @@ -371,6 +371,15 @@ if(BUILD_GUI) set(INDICATEQT_LIBRARIES "") endif(WITH_LIBINDICATE AND NOT WITH_QT5) + # Setup OS X notification center support + if(WITH_NOTIFICATION_CENTER AND APPLE) + set(HAVE_NOTIFICATION_CENTER true) + add_definitions(-DHAVE_NOTIFICATION_CENTER) + set(CLIENT_LIBRARIES ${CLIENT_LIBRARIES} + /System/Library/Frameworks/Foundation.framework + ) + endif() + endif(BUILD_GUI) # Core-only deps diff --git a/scripts/build/Info.plist b/scripts/build/Info.plist index c0093c62..ccfc721a 100644 --- a/scripts/build/Info.plist +++ b/scripts/build/Info.plist @@ -28,6 +28,8 @@ NSPrincipalClass NSApplication + NSHighResolutionCapable + NSHumanReadableCopyright © 2005-2012, Quassel IRC Team diff --git a/src/client/coreconnection.cpp b/src/client/coreconnection.cpp index 8fc5c515..fb553fec 100644 --- a/src/client/coreconnection.cpp +++ b/src/client/coreconnection.cpp @@ -28,14 +28,14 @@ #include "clientsettings.h" #include "coreaccountmodel.h" #include "identity.h" -#include "internalconnection.h" +#include "internalpeer.h" #include "network.h" #include "networkmodel.h" #include "quassel.h" #include "signalproxy.h" #include "util.h" -#include "protocols/legacy/legacyconnection.h" +#include "protocols/legacy/legacypeer.h" CoreConnection::CoreConnection(CoreAccountModel *model, QObject *parent) : QObject(parent), @@ -123,7 +123,7 @@ void CoreConnection::updateProgress(int value, int max) void CoreConnection::reconnectTimeout() { - if (!_connection) { + if (!_peer) { CoreConnectionSettings s; if (_wantReconnect && s.autoReconnect()) { #ifdef HAVE_KDE @@ -201,7 +201,7 @@ void CoreConnection::solidNetworkStatusChanged(Solid::Networking::Status status) bool CoreConnection::isEncrypted() const { - return _connection && _connection->isSecure(); + return _peer && _peer->isSecure(); } @@ -211,7 +211,7 @@ bool CoreConnection::isLocalConnection() const return false; if (currentAccount().isInternal()) return true; - if (_connection->isLocal()) + if (_peer->isLocal()) return true; return false; @@ -331,10 +331,10 @@ void CoreConnection::coreHasData(const QVariant &item) // if the connection is an orphan, the signalProxy adopts it. // -> we don't need to care about it anymore - disconnect(_connection, 0, this, 0); + disconnect(_peer, 0, this, 0); - _connection->setParent(0); - Client::signalProxy()->addPeer(_connection); + _peer->setParent(0); + Client::signalProxy()->addPeer(_peer); sessionStateReceived(msg["SessionState"].toMap()); } @@ -378,15 +378,15 @@ void CoreConnection::resetConnection(bool wantReconnect) _wantReconnect = wantReconnect; - if (_connection) { + if (_peer) { disconnect(_socket, 0, this, 0); - disconnect(_connection, 0, this, 0); - _connection->close(); + disconnect(_peer, 0, this, 0); + _peer->close(); - if (_connection->parent() == this) - _connection->deleteLater(); // if it's not us, it belongs to the sigproxy which will delete it + if (_peer->parent() == this) + _peer->deleteLater(); // if it's not us, it belongs to the sigproxy which will delete it _socket = 0; // socket is owned and will be deleted by RemoteConnection - _connection = 0; + _peer = 0; } else if (_socket) { disconnect(_socket, 0, this, 0); @@ -475,9 +475,9 @@ void CoreConnection::connectToCurrentAccount() } emit startInternalCore(); - InternalConnection *conn = new InternalConnection(); - Client::instance()->signalProxy()->addPeer(conn); // sigproxy will take ownership - emit connectToInternalCore(conn); + InternalPeer *peer = new InternalPeer(); + Client::instance()->signalProxy()->addPeer(peer); // sigproxy will take ownership + emit connectToInternalCore(peer); return; } @@ -525,10 +525,10 @@ void CoreConnection::connectToCurrentAccount() void CoreConnection::coreSocketConnected() { // Create the connection which will handle the incoming data - Q_ASSERT(!_connection); - _connection = new LegacyConnection(_socket, this); - connect(_connection, SIGNAL(dataReceived(QVariant)), SLOT(coreHasData(QVariant))); - connect(_connection, SIGNAL(transferProgress(int,int)), SLOT(updateProgress(int,int))); + Q_ASSERT(!_peer); + _peer = new LegacyPeer(_socket, this); + connect(_peer, SIGNAL(dataReceived(QVariant)), SLOT(coreHasData(QVariant))); + connect(_peer, SIGNAL(transferProgress(int,int)), SLOT(updateProgress(int,int))); // Phase One: Send client info and wait for core info @@ -546,7 +546,7 @@ void CoreConnection::coreSocketConnected() clientInit["UseCompression"] = false; #endif - qobject_cast(_connection)->writeSocketData(clientInit); + qobject_cast(_peer)->writeSocketData(clientInit); } @@ -695,7 +695,7 @@ void CoreConnection::loginToCore(const QString &prevError) clientLogin["MsgType"] = "ClientLogin"; clientLogin["User"] = currentAccount().user(); clientLogin["Password"] = currentAccount().password(); - qobject_cast(_connection)->writeSocketData(clientLogin); + qobject_cast(_peer)->writeSocketData(clientLogin); } @@ -809,5 +809,5 @@ void CoreConnection::doCoreSetup(const QVariant &setupData) QVariantMap setup; setup["MsgType"] = "CoreSetupData"; setup["SetupData"] = setupData; - qobject_cast(_connection)->writeSocketData(setup); + qobject_cast(_peer)->writeSocketData(setup); } diff --git a/src/client/coreconnection.h b/src/client/coreconnection.h index f6ff7ef8..836d8cc2 100644 --- a/src/client/coreconnection.h +++ b/src/client/coreconnection.h @@ -37,11 +37,11 @@ #endif #include "coreaccount.h" -#include "remoteconnection.h" +#include "remotepeer.h" #include "types.h" class CoreAccountModel; -class InternalConnection; +class InternalPeer; class Network; class SignalProxy; @@ -107,7 +107,7 @@ signals: void coreSetupFailed(const QString &error); void startInternalCore(); - void connectToInternalCore(InternalConnection *connection); + void connectToInternalCore(InternalPeer *connection); // These signals MUST be handled synchronously! void userAuthenticationRequired(CoreAccount *, bool *valid, const QString &errorMessage = QString()); @@ -176,7 +176,7 @@ private: QVariantMap _coreMsgBuffer; QPointer _socket; - QPointer _connection; + QPointer _peer; ConnectionState _state; QTimer _reconnectTimer; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 3043bb12..c247eb34 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -17,7 +17,7 @@ set(SOURCES eventmanager.cpp identity.cpp ignorelistmanager.cpp - internalconnection.cpp + internalpeer.cpp ircchannel.cpp ircevent.cpp irclisthelper.cpp @@ -29,13 +29,13 @@ set(SOURCES networkconfig.cpp networkevent.cpp quassel.cpp - remoteconnection.cpp + remotepeer.cpp settings.cpp signalproxy.cpp syncableobject.cpp util.cpp - protocols/legacy/legacyconnection.cpp + protocols/legacy/legacypeer.cpp ) set(MOC_HDRS @@ -49,18 +49,18 @@ set(MOC_HDRS eventmanager.h identity.h ignorelistmanager.h - internalconnection.h + internalpeer.h ircchannel.h irclisthelper.h ircuser.h network.h networkconfig.h - remoteconnection.h + remotepeer.h settings.h signalproxy.h syncableobject.h - protocols/legacy/legacyconnection.h + protocols/legacy/legacypeer.h ) set(HEADERS ${MOC_HDRS} @@ -78,6 +78,11 @@ set(HEADERS ${MOC_HDRS} types.h util.h) +if (HAVE_QCA2) + set(SOURCES ${SOURCES} keyevent.cpp) + set(HEADERS ${HEADERS} keyevent.h) +endif(HAVE_QCA2) + if(APPLE) set(SOURCES ${SOURCES} mac_utils.cpp) set(HEADERS ${HEADERS} mac_utils.h) diff --git a/src/common/aliasmanager.cpp b/src/common/aliasmanager.cpp index 002309de..d4e02a24 100644 --- a/src/common/aliasmanager.cpp +++ b/src/common/aliasmanager.cpp @@ -102,6 +102,7 @@ AliasManager::AliasList AliasManager::defaults() << Alias("chanserv", "/msg chanserv $0") << Alias("hs", "/msg hostserv $0") << Alias("hostserv", "/msg hostserv $0") + << Alias("wii", "/whois $0 $0") << Alias("back", "/quote away"); #ifdef Q_OS_LINUX diff --git a/src/common/eventmanager.h b/src/common/eventmanager.h index 3dbd7262..edebe617 100644 --- a/src/common/eventmanager.h +++ b/src/common/eventmanager.h @@ -113,6 +113,10 @@ public : CtcpEvent = 0x00050000, CtcpEventFlush + +#ifdef HAVE_QCA2 + ,KeyEvent = 0x00060000 +#endif }; EventManager(QObject *parent = 0); diff --git a/src/common/genversion.cpp b/src/common/genversion.cpp index 64a1da68..c4541f37 100644 --- a/src/common/genversion.cpp +++ b/src/common/genversion.cpp @@ -28,6 +28,7 @@ #include #include #include +#include int main(int argc, char **argv) { @@ -35,8 +36,11 @@ int main(int argc, char **argv) qFatal("Usage: ./genversion "); return 255; } - QString gitroot = argv[1]; - QString target = argv[2]; + + QCoreApplication app(argc, argv); + + QString gitroot = app.arguments()[1]; + QString target = app.arguments()[2]; QString basever, protover, clientneeds, coreneeds, descrver, dirty; QString committish, commitdate; diff --git a/src/common/internalconnection.cpp b/src/common/internalpeer.cpp similarity index 80% rename from src/common/internalconnection.cpp rename to src/common/internalpeer.cpp index 2dda1382..15e67ed3 100644 --- a/src/common/internalconnection.cpp +++ b/src/common/internalpeer.cpp @@ -21,7 +21,7 @@ #include #include -#include "internalconnection.h" +#include "internalpeer.h" using namespace Protocol; @@ -29,14 +29,14 @@ template class PeerMessageEvent : public QEvent { public: - PeerMessageEvent(InternalConnection *sender, InternalConnection::EventType eventType, const T &message) + PeerMessageEvent(InternalPeer *sender, InternalPeer::EventType eventType, const T &message) : QEvent(QEvent::Type(eventType)), sender(sender), message(message) {} - InternalConnection *sender; + InternalPeer *sender; T message; }; -InternalConnection::InternalConnection(QObject *parent) +InternalPeer::InternalPeer(QObject *parent) : SignalProxy::AbstractPeer(parent), _proxy(0), _peer(0), @@ -46,38 +46,38 @@ InternalConnection::InternalConnection(QObject *parent) } -InternalConnection::~InternalConnection() +InternalPeer::~InternalPeer() { if (_isOpen) emit disconnected(); } -QString InternalConnection::description() const +QString InternalPeer::description() const { return tr("internal connection"); } -bool InternalConnection::isOpen() const +bool InternalPeer::isOpen() const { return true; } -bool InternalConnection::isSecure() const +bool InternalPeer::isSecure() const { return true; } -bool InternalConnection::isLocal() const +bool InternalPeer::isLocal() const { return true; } -void InternalConnection::close(const QString &reason) +void InternalPeer::close(const QString &reason) { // FIXME Q_UNUSED(reason) @@ -85,13 +85,13 @@ void InternalConnection::close(const QString &reason) } -int InternalConnection::lag() const +int InternalPeer::lag() const { return 0; } -void InternalConnection::setSignalProxy(SignalProxy *proxy) +void InternalPeer::setSignalProxy(::SignalProxy *proxy) { if (!proxy && _proxy) { _proxy = 0; @@ -111,7 +111,7 @@ void InternalConnection::setSignalProxy(SignalProxy *proxy) } -void InternalConnection::setPeer(InternalConnection *peer) +void InternalPeer::setPeer(InternalPeer *peer) { if (_peer) { qWarning() << Q_FUNC_INFO << "Peer already set, ignoring!"; @@ -122,7 +122,7 @@ void InternalConnection::setPeer(InternalConnection *peer) } -void InternalConnection::peerDisconnected() +void InternalPeer::peerDisconnected() { disconnect(_peer, 0, this, 0); _peer = 0; @@ -133,32 +133,32 @@ void InternalConnection::peerDisconnected() } -void InternalConnection::dispatch(const SyncMessage &msg) +void InternalPeer::dispatch(const SyncMessage &msg) { dispatch(SyncMessageEvent, msg); } -void InternalConnection::dispatch(const RpcCall &msg) +void InternalPeer::dispatch(const RpcCall &msg) { dispatch(RpcCallEvent, msg); } -void InternalConnection::dispatch(const InitRequest &msg) +void InternalPeer::dispatch(const InitRequest &msg) { dispatch(InitRequestEvent, msg); } -void InternalConnection::dispatch(const InitData &msg) +void InternalPeer::dispatch(const InitData &msg) { dispatch(InitDataEvent, msg); } template -void InternalConnection::dispatch(EventType eventType, const T &msg) +void InternalPeer::dispatch(EventType eventType, const T &msg) { if (!_peer) { qWarning() << Q_FUNC_INFO << "Cannot dispatch a message without a peer!"; @@ -173,7 +173,7 @@ void InternalConnection::dispatch(EventType eventType, const T &msg) template -void InternalConnection::handle(const T &msg) +void InternalPeer::handle(const T &msg) { if (!_proxy) { qWarning() << Q_FUNC_INFO << "Cannot handle a message without having a signal proxy set!"; @@ -184,7 +184,7 @@ void InternalConnection::handle(const T &msg) } -void InternalConnection::customEvent(QEvent *event) +void InternalPeer::customEvent(QEvent *event) { switch ((int)event->type()) { case SyncMessageEvent: { diff --git a/src/common/internalconnection.h b/src/common/internalpeer.h similarity index 89% rename from src/common/internalconnection.h rename to src/common/internalpeer.h index dd17f033..4c82ceb3 100644 --- a/src/common/internalconnection.h +++ b/src/common/internalpeer.h @@ -18,8 +18,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef INTERNALCONNECTION_H -#define INTERNALCONNECTION_H +#ifndef INTERNALPEER_H +#define INTERNALPEER_H #include @@ -28,7 +28,7 @@ class QEvent; -class InternalConnection : public SignalProxy::AbstractPeer +class InternalPeer : public SignalProxy::AbstractPeer { Q_OBJECT @@ -40,16 +40,16 @@ public: InitDataEvent }; - InternalConnection(QObject *parent = 0); - virtual ~InternalConnection(); + InternalPeer(QObject *parent = 0); + virtual ~InternalPeer(); QString description() const; SignalProxy *signalProxy() const; void setSignalProxy(SignalProxy *proxy); - InternalConnection *peer() const; - void setPeer(InternalConnection *peer); + InternalPeer *peer() const; + void setPeer(InternalPeer *peer); bool isOpen() const; bool isSecure() const; @@ -85,7 +85,7 @@ private: private: SignalProxy *_proxy; - InternalConnection *_peer; + InternalPeer *_peer; bool _isOpen; }; diff --git a/src/common/keyevent.cpp b/src/common/keyevent.cpp new file mode 100644 index 00000000..afeca219 --- /dev/null +++ b/src/common/keyevent.cpp @@ -0,0 +1,47 @@ +/*************************************************************************** + * Copyright (C) 2013 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "keyevent.h" + +Event *KeyEvent::create(EventManager::EventType type, QVariantMap &map, Network *network) +{ + if (type == EventManager::KeyEvent) + return new KeyEvent(type, map, network); + + return 0; +} + + +KeyEvent::KeyEvent(EventManager::EventType type, QVariantMap &map, Network *network) + : IrcEvent(type, map, network) +{ + _exchangeType = static_cast(map.take("exchangeType").toInt()); + _target = map.take("target").toString(); + _key = map.take("key").toByteArray(); +} + + +void KeyEvent::toVariantMap(QVariantMap &map) const +{ + IrcEvent::toVariantMap(map); + map["exchangeType"] = exchangeType(); + map["target"] = target(); + map["key"] = key(); +} diff --git a/src/common/keyevent.h b/src/common/keyevent.h new file mode 100644 index 00000000..0e7b3b87 --- /dev/null +++ b/src/common/keyevent.h @@ -0,0 +1,79 @@ +/*************************************************************************** + * Copyright (C) 2013 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef KEYEVENT_H +#define KEYEVENT_H + +#include "ircevent.h" + +class KeyEvent : public IrcEvent +{ +public: + enum ExchangeType { + Init, + Finish + }; + + explicit KeyEvent(EventManager::EventType type, Network *network, const QString &prefix, const QString &target, + ExchangeType exchangeType, const QByteArray &key, + const QDateTime ×tamp = QDateTime()) + : IrcEvent(type, network, prefix), + _exchangeType(exchangeType), + _target(target), + _key(key) + { + setTimestamp(timestamp); + } + + + inline ExchangeType exchangeType() const { return _exchangeType; } + inline void setExchangeType(ExchangeType type) { _exchangeType = type; } + + inline QString target() const { return _target; } + inline void setTarget(const QString &target) { _target = target; } + + inline QByteArray key() const { return _key; } + inline void setKey(const QByteArray &key) { _key = key; } + + static Event *create(EventManager::EventType type, QVariantMap &map, Network *network); + +protected: + explicit KeyEvent(EventManager::EventType type, QVariantMap &map, Network *network); + void toVariantMap(QVariantMap &map) const; + + virtual inline QString className() const { return "KeyEvent"; } + virtual inline void debugInfo(QDebug &dbg) const + { + NetworkEvent::debugInfo(dbg); + dbg << ", prefix = " << qPrintable(prefix()) + << ", target = " << qPrintable(target()) + << ", exchangetype = " << (exchangeType() == Init ? "init" : "finish") + << ", key = " << qPrintable(key()); + } + + +private: + ExchangeType _exchangeType; + QString _target; + QByteArray _key; +}; + + +#endif diff --git a/src/common/networkconfig.cpp b/src/common/networkconfig.cpp index 17a37b42..066988f8 100644 --- a/src/common/networkconfig.cpp +++ b/src/common/networkconfig.cpp @@ -29,7 +29,8 @@ NetworkConfig::NetworkConfig(const QString &objectName, QObject *parent) _autoWhoEnabled(true), _autoWhoInterval(90), _autoWhoNickLimit(200), - _autoWhoDelay(5) + _autoWhoDelay(5), + _standardCtcp(false) { } @@ -107,3 +108,14 @@ void NetworkConfig::setAutoWhoDelay(int delay) SYNC(ARG(delay)) emit autoWhoDelaySet(delay); } + + +void NetworkConfig::setStandardCtcp(bool enabled) +{ + if (_standardCtcp == enabled) + return; + + _standardCtcp = enabled; + SYNC(ARG(enabled)) + emit standardCtcpSet(enabled); +} diff --git a/src/common/networkconfig.h b/src/common/networkconfig.h index 3d18077b..ae121aa5 100644 --- a/src/common/networkconfig.h +++ b/src/common/networkconfig.h @@ -35,6 +35,7 @@ class NetworkConfig : public SyncableObject Q_PROPERTY(int autoWhoInterval READ autoWhoInterval WRITE setAutoWhoInterval) Q_PROPERTY(int autoWhoNickLimit READ autoWhoNickLimit WRITE setAutoWhoNickLimit) Q_PROPERTY(int autoWhoDelay READ autoWhoDelay WRITE setAutoWhoDelay) + Q_PROPERTY(bool standardCtcp READ standardCtcp WRITE setStandardCtcp) public : NetworkConfig(const QString &objectName = "GlobalNetworkConfig", QObject *parent = 0); @@ -70,6 +71,10 @@ public slots: void setAutoWhoDelay(int); virtual inline void requestSetAutoWhoDelay(int i) { REQUEST(ARG(i)) } + inline bool standardCtcp() const { return _standardCtcp; } + void setStandardCtcp(bool); + virtual inline void requestSetStandardCtcp(bool b) { REQUEST(ARG(b)) } + signals: void pingTimeoutEnabledSet(bool); void pingIntervalSet(int); @@ -78,6 +83,7 @@ signals: void autoWhoIntervalSet(int); // void autoWhoNickLimitSet(int); void autoWhoDelaySet(int); + void standardCtcpSet(bool); // void setPingTimeoutEnabledRequested(bool); // void setPingIntervalRequested(int); @@ -96,6 +102,8 @@ private: int _autoWhoInterval; int _autoWhoNickLimit; int _autoWhoDelay; + + bool _standardCtcp; }; diff --git a/src/common/protocols/legacy/legacyconnection.cpp b/src/common/protocols/legacy/legacypeer.cpp similarity index 89% rename from src/common/protocols/legacy/legacyconnection.cpp rename to src/common/protocols/legacy/legacypeer.cpp index a9969a98..709291f5 100644 --- a/src/common/protocols/legacy/legacyconnection.cpp +++ b/src/common/protocols/legacy/legacypeer.cpp @@ -18,12 +18,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#include "legacyconnection.h" +#include "legacypeer.h" using namespace Protocol; -LegacyConnection::LegacyConnection(QTcpSocket *socket, QObject *parent) - : RemoteConnection(socket, parent), +LegacyPeer::LegacyPeer(QTcpSocket *socket, QObject *parent) + : RemotePeer(socket, parent), _blockSize(0), _useCompression(false) { @@ -34,9 +34,9 @@ LegacyConnection::LegacyConnection(QTcpSocket *socket, QObject *parent) } -void LegacyConnection::setSignalProxy(SignalProxy *proxy) +void LegacyPeer::setSignalProxy(::SignalProxy *proxy) { - RemoteConnection::setSignalProxy(proxy); + RemotePeer::setSignalProxy(proxy); if (proxy) { // enable compression now if requested - the initial handshake is uncompressed in the legacy protocol! @@ -46,7 +46,7 @@ void LegacyConnection::setSignalProxy(SignalProxy *proxy) } -void LegacyConnection::socketDataAvailable() +void LegacyPeer::socketDataAvailable() { QVariant item; while (readSocketData(item)) { @@ -59,7 +59,7 @@ void LegacyConnection::socketDataAvailable() } -bool LegacyConnection::readSocketData(QVariant &item) +bool LegacyPeer::readSocketData(QVariant &item) { if (_blockSize == 0) { if (socket()->bytesAvailable() < 4) @@ -118,7 +118,7 @@ bool LegacyConnection::readSocketData(QVariant &item) } -void LegacyConnection::writeSocketData(const QVariant &item) +void LegacyPeer::writeSocketData(const QVariant &item) { if (!socket()->isOpen()) { qWarning() << Q_FUNC_INFO << "Can't write to a closed socket!"; @@ -147,7 +147,7 @@ void LegacyConnection::writeSocketData(const QVariant &item) } -void LegacyConnection::handlePackedFunc(const QVariant &packedFunc) +void LegacyPeer::handlePackedFunc(const QVariant &packedFunc) { QVariantList params(packedFunc.toList()); @@ -228,43 +228,43 @@ void LegacyConnection::handlePackedFunc(const QVariant &packedFunc) } -void LegacyConnection::dispatch(const Protocol::SyncMessage &msg) +void LegacyPeer::dispatch(const Protocol::SyncMessage &msg) { dispatchPackedFunc(QVariantList() << (qint16)Sync << msg.className() << msg.objectName() << msg.slotName() << msg.params()); } -void LegacyConnection::dispatch(const Protocol::RpcCall &msg) +void LegacyPeer::dispatch(const Protocol::RpcCall &msg) { dispatchPackedFunc(QVariantList() << (qint16)RpcCall << msg.slotName() << msg.params()); } -void LegacyConnection::dispatch(const Protocol::InitRequest &msg) +void LegacyPeer::dispatch(const Protocol::InitRequest &msg) { dispatchPackedFunc(QVariantList() << (qint16)InitRequest << msg.className() << msg.objectName()); } -void LegacyConnection::dispatch(const Protocol::InitData &msg) +void LegacyPeer::dispatch(const Protocol::InitData &msg) { dispatchPackedFunc(QVariantList() << (qint16)InitData << msg.className() << msg.objectName() << msg.initData()); } -void LegacyConnection::dispatch(const Protocol::HeartBeat &msg) +void LegacyPeer::dispatch(const Protocol::HeartBeat &msg) { dispatchPackedFunc(QVariantList() << (qint16)HeartBeat << msg.timestamp().time()); } -void LegacyConnection::dispatch(const Protocol::HeartBeatReply &msg) +void LegacyPeer::dispatch(const Protocol::HeartBeatReply &msg) { dispatchPackedFunc(QVariantList() << (qint16)HeartBeatReply << msg.timestamp().time()); } -void LegacyConnection::dispatchPackedFunc(const QVariantList &packedFunc) +void LegacyPeer::dispatchPackedFunc(const QVariantList &packedFunc) { writeSocketData(QVariant(packedFunc)); } diff --git a/src/common/protocols/legacy/legacyconnection.h b/src/common/protocols/legacy/legacypeer.h similarity index 91% rename from src/common/protocols/legacy/legacyconnection.h rename to src/common/protocols/legacy/legacypeer.h index 04ac1c36..a3aa178b 100644 --- a/src/common/protocols/legacy/legacyconnection.h +++ b/src/common/protocols/legacy/legacypeer.h @@ -18,16 +18,16 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef LEGACYCONNECTION_H -#define LEGACYCONNECTION_H +#ifndef LEGACYPEER_H +#define LEGACYPEER_H #include -#include "../../remoteconnection.h" +#include "../../remotepeer.h" class QDataStream; -class LegacyConnection : public RemoteConnection +class LegacyPeer : public RemotePeer { Q_OBJECT @@ -41,8 +41,8 @@ public: HeartBeatReply }; - LegacyConnection(QTcpSocket *socket, QObject *parent = 0); - ~LegacyConnection() {} + LegacyPeer(QTcpSocket *socket, QObject *parent = 0); + ~LegacyPeer() {} void setSignalProxy(SignalProxy *proxy); diff --git a/src/common/quassel.cpp b/src/common/quassel.cpp index e9763fc7..c60f5ec1 100644 --- a/src/common/quassel.cpp +++ b/src/common/quassel.cpp @@ -40,6 +40,7 @@ #include "bufferinfo.h" #include "types.h" #include "syncableobject.h" +#include "logger.h" Quassel::BuildInfo Quassel::_buildInfo; AbstractCliParser *Quassel::_cliParser = 0; @@ -494,10 +495,32 @@ void Quassel::loadTranslation(const QLocale &locale) quasselTranslator->setObjectName("QuasselTr"); qApp->installTranslator(quasselTranslator); - QLocale::setDefault(locale); +#if QT_VERSION >= 0x040800 + bool success = qtTranslator->load(locale, QString("qt_%1"), translationDirPath()); + if (!success) + qtTranslator->load(locale, QString("qt_"), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + quasselTranslator->load(locale, QString(""), translationDirPath()); +#else + QString localeName = locale.name(); + + // if the user did not specify a language in the settings, the system locale + // is used, but Qt < 4.8 does not respect language settings. This bit is + // based on QLocale::uiLanguages() as in Qt 4.8.3 + if (locale == QLocale::system()) { + // FIXME: does it make sense to set the locale to the system locale? + QLocale::setDefault(locale); + QVariant res = QSystemLocale().query(QSystemLocale::UILanguages, QVariant()); + if (!res.isNull()) { + QString newName = res.toStringList()[0]; + if (!newName.isEmpty()) { + localeName = newName.replace('-', "_"); // silly Qt. + } + } + } - bool success = qtTranslator->load(QString("qt_%1").arg(locale.name()), translationDirPath()); + bool success = qtTranslator->load(QString("qt_%1").arg(localeName), translationDirPath()); if (!success) - qtTranslator->load(QString("qt_%1").arg(locale.name()), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); - quasselTranslator->load(QString("%1").arg(locale.name()), translationDirPath()); + qtTranslator->load(QString("qt_%1").arg(localeName), QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + quasselTranslator->load(QString("%1").arg(localeName), translationDirPath()); +#endif } diff --git a/src/common/quassel.h b/src/common/quassel.h index de19313a..6089ac03 100644 --- a/src/common/quassel.h +++ b/src/common/quassel.h @@ -71,8 +71,9 @@ public: enum Feature { SynchronizedMarkerLine = 0x0001, SaslAuthentication = 0x0002, + SaslExternal = 0x0004, - NumFeatures = 0x0002 + NumFeatures = 0x0004 }; Q_DECLARE_FLAGS(Features, Feature); diff --git a/src/common/remoteconnection.cpp b/src/common/remotepeer.cpp similarity index 86% rename from src/common/remoteconnection.cpp rename to src/common/remotepeer.cpp index c67d3c76..e33f56a9 100644 --- a/src/common/remoteconnection.cpp +++ b/src/common/remotepeer.cpp @@ -25,11 +25,11 @@ # include #endif -#include "remoteconnection.h" +#include "remotepeer.h" using namespace Protocol; -RemoteConnection::RemoteConnection(QTcpSocket *socket, QObject *parent) +RemotePeer::RemotePeer(QTcpSocket *socket, QObject *parent) : SignalProxy::AbstractPeer(parent), _socket(socket), _signalProxy(0), @@ -51,7 +51,7 @@ RemoteConnection::RemoteConnection(QTcpSocket *socket, QObject *parent) } -QString RemoteConnection::description() const +QString RemotePeer::description() const { if (socket()) return socket()->peerAddress().toString(); @@ -60,13 +60,13 @@ QString RemoteConnection::description() const } -SignalProxy *RemoteConnection::signalProxy() const +::SignalProxy *RemotePeer::signalProxy() const { return _signalProxy; } -void RemoteConnection::setSignalProxy(SignalProxy *proxy) +void RemotePeer::setSignalProxy(::SignalProxy *proxy) { if (proxy == _signalProxy) return; @@ -91,7 +91,7 @@ void RemoteConnection::setSignalProxy(SignalProxy *proxy) } -void RemoteConnection::changeHeartBeatInterval(int secs) +void RemotePeer::changeHeartBeatInterval(int secs) { if(secs <= 0) _heartBeatTimer->stop(); @@ -102,19 +102,19 @@ void RemoteConnection::changeHeartBeatInterval(int secs) } -int RemoteConnection::lag() const +int RemotePeer::lag() const { return _lag; } -QTcpSocket *RemoteConnection::socket() const +QTcpSocket *RemotePeer::socket() const { return _socket; } -bool RemoteConnection::isSecure() const +bool RemotePeer::isSecure() const { if (socket()) { if (isLocal()) @@ -129,7 +129,7 @@ bool RemoteConnection::isSecure() const } -bool RemoteConnection::isLocal() const +bool RemotePeer::isLocal() const { if (socket()) { if (socket()->peerAddress() == QHostAddress::LocalHost || socket()->peerAddress() == QHostAddress::LocalHostIPv6) @@ -139,13 +139,13 @@ bool RemoteConnection::isLocal() const } -bool RemoteConnection::isOpen() const +bool RemotePeer::isOpen() const { return socket() && socket()->state() == QTcpSocket::ConnectedState; } -void RemoteConnection::close(const QString &reason) +void RemotePeer::close(const QString &reason) { if (!reason.isEmpty()) { qWarning() << "Disconnecting:" << reason; @@ -157,13 +157,13 @@ void RemoteConnection::close(const QString &reason) } -void RemoteConnection::handle(const HeartBeat &heartBeat) +void RemotePeer::handle(const HeartBeat &heartBeat) { dispatch(HeartBeatReply(heartBeat.timestamp())); } -void RemoteConnection::handle(const HeartBeatReply &heartBeatReply) +void RemotePeer::handle(const HeartBeatReply &heartBeatReply) { _heartBeatCount = 0; #if QT_VERSION < 0x040700 @@ -174,7 +174,7 @@ void RemoteConnection::handle(const HeartBeatReply &heartBeatReply) } -void RemoteConnection::sendHeartBeat() +void RemotePeer::sendHeartBeat() { if (signalProxy()->maxHeartBeatCount() > 0 && _heartBeatCount >= signalProxy()->maxHeartBeatCount()) { qWarning() << "Disconnecting peer:" << description() diff --git a/src/common/remoteconnection.h b/src/common/remotepeer.h similarity index 92% rename from src/common/remoteconnection.h rename to src/common/remotepeer.h index 6d12d70f..e41a6a3b 100644 --- a/src/common/remoteconnection.h +++ b/src/common/remotepeer.h @@ -18,8 +18,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef REMOTECONNECTION_H -#define REMOTECONNECTION_H +#ifndef REMOTEPEER_H +#define REMOTEPEER_H #include #include @@ -29,13 +29,13 @@ class QTimer; -class RemoteConnection : public SignalProxy::AbstractPeer +class RemotePeer : public SignalProxy::AbstractPeer { Q_OBJECT public: - RemoteConnection(QTcpSocket *socket, QObject *parent = 0); - virtual ~RemoteConnection() {}; + RemotePeer(QTcpSocket *socket, QObject *parent = 0); + virtual ~RemotePeer() {}; void setSignalProxy(SignalProxy *proxy); @@ -91,10 +91,9 @@ private: int _lag; }; - // Template methods we need in the header template inline -void RemoteConnection::handle(const T &protoMessage) +void RemotePeer::handle(const T &protoMessage) { if (!signalProxy()) { qWarning() << Q_FUNC_INFO << "Cannot handle messages without a SignalProxy!"; diff --git a/src/common/signalproxy.h b/src/common/signalproxy.h index 7f70f7e2..d446fefc 100644 --- a/src/common/signalproxy.h +++ b/src/common/signalproxy.h @@ -168,8 +168,8 @@ private: friend class SignalRelay; friend class SyncableObject; - friend class InternalConnection; - friend class RemoteConnection; + friend class InternalPeer; + friend class RemotePeer; }; diff --git a/src/core/cipher.cpp b/src/core/cipher.cpp index 5ca31293..15a986b2 100644 --- a/src/core/cipher.cpp +++ b/src/core/cipher.cpp @@ -35,8 +35,10 @@ Cipher::~Cipher() bool Cipher::setKey(QByteArray key) { - if (key.isEmpty()) + if (key.isEmpty()) { + m_key.clear(); return false; + } if (key.mid(0, 4).toLower() == "ecb:") { diff --git a/src/core/core.cpp b/src/core/core.cpp index e7c56e55..4413211e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -23,17 +23,16 @@ #include "core.h" #include "coresession.h" #include "coresettings.h" -#include "internalconnection.h" +#include "internalpeer.h" #include "postgresqlstorage.h" #include "quassel.h" -#include "signalproxy.h" #include "sqlitestorage.h" #include "network.h" #include "logger.h" #include "util.h" -#include "protocols/legacy/legacyconnection.h" +#include "protocols/legacy/legacypeer.h" // migration related #include @@ -57,8 +56,8 @@ const int Core::AddClientEventId = QEvent::registerEventType(); class AddClientEvent : public QEvent { public: - AddClientEvent(RemoteConnection *connection, UserId uid) : QEvent(QEvent::Type(Core::AddClientEventId)), connection(connection), userId(uid) {} - RemoteConnection *connection; + AddClientEvent(RemotePeer *p, UserId uid) : QEvent(QEvent::Type(Core::AddClientEventId)), peer(p), userId(uid) {} + RemotePeer *peer; UserId userId; }; @@ -218,8 +217,8 @@ void Core::init() Core::~Core() { - foreach(RemoteConnection *connection, clientInfo.keys()) { - connection->close(); // disconnect non authed clients + foreach(RemotePeer *peer, clientInfo.keys()) { + peer->close(); // disconnect non authed clients } qDeleteAll(sessions); qDeleteAll(_storageBackends); @@ -518,13 +517,13 @@ void Core::incomingConnection() Q_ASSERT(server); while (server->hasPendingConnections()) { QTcpSocket *socket = server->nextPendingConnection(); - RemoteConnection *connection = new LegacyConnection(socket, this); + RemotePeer *peer = new LegacyPeer(socket, this); - connect(connection, SIGNAL(disconnected()), SLOT(clientDisconnected())); - connect(connection, SIGNAL(dataReceived(QVariant)), SLOT(processClientMessage(QVariant))); - connect(connection, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); + connect(peer, SIGNAL(disconnected()), SLOT(clientDisconnected())); + connect(peer, SIGNAL(dataReceived(QVariant)), SLOT(processClientMessage(QVariant))); + connect(peer, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(socketError(QAbstractSocket::SocketError))); - clientInfo.insert(connection, QVariantMap()); + clientInfo.insert(peer, QVariantMap()); quInfo() << qPrintable(tr("Client connected from")) << qPrintable(socket->peerAddress().toString()); if (!_configured) { @@ -536,8 +535,8 @@ void Core::incomingConnection() void Core::processClientMessage(const QVariant &data) { - RemoteConnection *connection = qobject_cast(sender()); - if (!connection) { + RemotePeer *peer = qobject_cast(sender()); + if (!peer) { qWarning() << Q_FUNC_INFO << "Message not sent by RemoteConnection!"; return; } @@ -546,7 +545,7 @@ void Core::processClientMessage(const QVariant &data) if (!msg.contains("MsgType")) { // Client is way too old, does not even use the current init format qWarning() << qPrintable(tr("Antique client trying to connect... refusing.")); - connection->close(); + peer->close(); return; } @@ -561,9 +560,9 @@ void Core::processClientMessage(const QVariant &data) reply["Error"] = tr("Your Quassel Client is too old!
" "This core needs at least client/core protocol version %1.
" "Please consider upgrading your client.").arg(Quassel::buildInfo().coreNeedsProtocol); - connection->writeSocketData(reply); - qWarning() << qPrintable(tr("Client")) << connection->description() << qPrintable(tr("too old, rejecting.")); - connection->close(); + peer->writeSocketData(reply); + qWarning() << qPrintable(tr("Client")) << peer->description() << qPrintable(tr("too old, rejecting.")); + peer->close(); return; } @@ -590,7 +589,7 @@ void Core::processClientMessage(const QVariant &data) #ifdef HAVE_SSL SslServer *sslServer = qobject_cast(&_server); - QSslSocket *sslSocket = qobject_cast(connection->socket()); + QSslSocket *sslSocket = qobject_cast(peer->socket()); bool supportSsl = sslServer && sslSocket && sslServer->isCertValid(); #else bool supportSsl = false; @@ -626,15 +625,15 @@ void Core::processClientMessage(const QVariant &data) else { reply["Configured"] = true; } - clientInfo[connection] = msg; // store for future reference + clientInfo[peer] = msg; // store for future reference reply["MsgType"] = "ClientInitAck"; - connection->writeSocketData(reply); - connection->socket()->flush(); // ensure that the write cache is flushed before we switch to ssl + peer->writeSocketData(reply); + peer->socket()->flush(); // ensure that the write cache is flushed before we switch to ssl #ifdef HAVE_SSL // after we told the client that we are ssl capable we switch to ssl mode if (supportSsl && msg["UseSsl"].toBool()) { - qDebug() << qPrintable(tr("Starting TLS for Client:")) << connection->description(); + qDebug() << qPrintable(tr("Starting TLS for Client:")) << peer->description(); connect(sslSocket, SIGNAL(sslErrors(const QList &)), SLOT(sslErrors(const QList &))); sslSocket->startServerEncryption(); } @@ -642,20 +641,20 @@ void Core::processClientMessage(const QVariant &data) #ifndef QT_NO_COMPRESS if (supportsCompression && msg["UseCompression"].toBool()) { - connection->socket()->setProperty("UseCompression", true); - qDebug() << "Using compression for Client:" << qPrintable(connection->socket()->peerAddress().toString()); + peer->socket()->setProperty("UseCompression", true); + qDebug() << "Using compression for Client:" << qPrintable(peer->socket()->peerAddress().toString()); } #endif } else { // for the rest, we need an initialized connection - if (!clientInfo.contains(connection)) { + if (!clientInfo.contains(peer)) { QVariantMap reply; reply["MsgType"] = "ClientLoginReject"; reply["Error"] = tr("Client not initialized!
You need to send an init message before trying to login."); - connection->writeSocketData(reply); - qWarning() << qPrintable(tr("Client")) << qPrintable(connection->socket()->peerAddress().toString()) << qPrintable(tr("did not send an init message before trying to login, rejecting.")); - connection->close(); return; + peer->writeSocketData(reply); + qWarning() << qPrintable(tr("Client")) << qPrintable(peer->socket()->peerAddress().toString()) << qPrintable(tr("did not send an init message before trying to login, rejecting.")); + peer->close(); return; } if (msg["MsgType"] == "CoreSetupData") { QVariantMap reply; @@ -667,7 +666,7 @@ void Core::processClientMessage(const QVariant &data) else { reply["MsgType"] = "CoreSetupAck"; } - connection->writeSocketData(reply); + peer->writeSocketData(reply); } else if (msg["MsgType"] == "ClientLogin") { QVariantMap reply; @@ -675,13 +674,13 @@ void Core::processClientMessage(const QVariant &data) if (uid == 0) { reply["MsgType"] = "ClientLoginReject"; reply["Error"] = tr("Invalid username or password!
The username/password combination you supplied could not be found in the database."); - connection->writeSocketData(reply); + peer->writeSocketData(reply); return; } reply["MsgType"] = "ClientLoginAck"; - connection->writeSocketData(reply); - quInfo() << qPrintable(tr("Client")) << qPrintable(connection->socket()->peerAddress().toString()) << qPrintable(tr("initialized and authenticated successfully as \"%1\" (UserId: %2).").arg(msg["User"].toString()).arg(uid.toInt())); - setupClientSession(connection, uid); + peer->writeSocketData(reply); + quInfo() << qPrintable(tr("Client")) << qPrintable(peer->socket()->peerAddress().toString()) << qPrintable(tr("initialized and authenticated successfully as \"%1\" (UserId: %2).").arg(msg["User"].toString()).arg(uid.toInt())); + setupClientSession(peer, uid); } } } @@ -690,12 +689,12 @@ void Core::processClientMessage(const QVariant &data) // Potentially called during the initialization phase (before handing the connection off to the session) void Core::clientDisconnected() { - RemoteConnection *connection = qobject_cast(sender()); - Q_ASSERT(connection); + RemotePeer *peer = qobject_cast(sender()); + Q_ASSERT(peer); - quInfo() << qPrintable(tr("Non-authed client disconnected.")) << qPrintable(connection->socket()->peerAddress().toString()); - clientInfo.remove(connection); - connection->deleteLater(); + quInfo() << qPrintable(tr("Non-authed client disconnected.")) << qPrintable(peer->socket()->peerAddress().toString()); + clientInfo.remove(peer); + peer->deleteLater(); // make server listen again if still not configured if (!_configured) { @@ -707,12 +706,12 @@ void Core::clientDisconnected() } -void Core::setupClientSession(RemoteConnection *connection, UserId uid) +void Core::setupClientSession(RemotePeer *peer, UserId uid) { // From now on everything is handled by the client session - disconnect(connection, 0, this, 0); - connection->socket()->flush(); - clientInfo.remove(connection); + disconnect(peer, 0, this, 0); + peer->socket()->flush(); + clientInfo.remove(peer); // Find or create session for validated user SessionThread *session; @@ -722,15 +721,15 @@ void Core::setupClientSession(RemoteConnection *connection, UserId uid) else { session = createSession(uid); if (!session) { - qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(connection->socket()->peerAddress().toString()); - connection->close(); + qWarning() << qPrintable(tr("Could not initialize session for client:")) << qPrintable(peer->socket()->peerAddress().toString()); + peer->close(); return; } } // as we are currently handling an event triggered by incoming data on this socket // it is unsafe to directly move the socket to the client thread. - QCoreApplication::postEvent(this, new AddClientEvent(connection, uid)); + QCoreApplication::postEvent(this, new AddClientEvent(peer, uid)); } @@ -738,27 +737,27 @@ void Core::customEvent(QEvent *event) { if (event->type() == AddClientEventId) { AddClientEvent *addClientEvent = static_cast(event); - addClientHelper(addClientEvent->connection, addClientEvent->userId); + addClientHelper(addClientEvent->peer, addClientEvent->userId); return; } } -void Core::addClientHelper(RemoteConnection *connection, UserId uid) +void Core::addClientHelper(RemotePeer *peer, UserId uid) { // Find or create session for validated user if (!sessions.contains(uid)) { - qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(connection->socket()->peerAddress().toString()); - connection->close(); + qWarning() << qPrintable(tr("Could not find a session for client:")) << qPrintable(peer->socket()->peerAddress().toString()); + peer->close(); return; } SessionThread *session = sessions[uid]; - session->addClient(connection); + session->addClient(peer); } -void Core::setupInternalClientSession(InternalConnection *clientConnection) +void Core::setupInternalClientSession(InternalPeer *clientPeer) { if (!_configured) { stopListening(); @@ -774,9 +773,9 @@ void Core::setupInternalClientSession(InternalConnection *clientConnection) return; } - InternalConnection *coreConnection = new InternalConnection(this); - coreConnection->setPeer(clientConnection); - clientConnection->setPeer(coreConnection); + InternalPeer *corePeer = new InternalPeer(this); + corePeer->setPeer(clientPeer); + clientPeer->setPeer(corePeer); // Find or create session for validated user SessionThread *sessionThread; @@ -785,7 +784,7 @@ void Core::setupInternalClientSession(InternalConnection *clientConnection) else sessionThread = createSession(uid); - sessionThread->addClient(coreConnection); + sessionThread->addClient(corePeer); } @@ -816,9 +815,9 @@ void Core::sslErrors(const QList &errors) void Core::socketError(QAbstractSocket::SocketError err) { - RemoteConnection *connection = qobject_cast(sender()); - if (connection && err != QAbstractSocket::RemoteHostClosedError) - qWarning() << "Core::socketError()" << connection->socket() << err << connection->socket()->errorString(); + RemotePeer *peer = qobject_cast(sender()); + if (peer && err != QAbstractSocket::RemoteHostClosedError) + qWarning() << "Core::socketError()" << peer->socket() << err << peer->socket()->errorString(); } diff --git a/src/core/core.h b/src/core/core.h index dfecbe00..ebe80619 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -42,7 +42,7 @@ #include "types.h" class CoreSession; -class RemoteConnection; +class RemotePeer; struct NetworkInfo; class SessionThread; class SignalProxy; @@ -485,7 +485,7 @@ public slots: /** \note This method is threadsafe. */ void syncStorage(); - void setupInternalClientSession(InternalConnection *clientConnection); + void setupInternalClientSession(InternalPeer *clientConnection); signals: //! Sent when a BufferInfo is updated in storage. @@ -520,8 +520,8 @@ private: static Core *instanceptr; SessionThread *createSession(UserId userId, bool restoreState = false); - void setupClientSession(RemoteConnection *connection, UserId uid); - void addClientHelper(RemoteConnection *connection, UserId uid); + void setupClientSession(RemotePeer *peer, UserId uid); + void addClientHelper(RemotePeer *peer, UserId uid); //void processCoreSetup(QTcpSocket *socket, QVariantMap &msg); QString setupCoreForInternalUsage(); QString setupCore(QVariantMap setupData); @@ -548,7 +548,7 @@ private: OidentdConfigGenerator *_oidentdConfigGenerator; - QHash clientInfo; + QHash clientInfo; QHash _storageBackends; diff --git a/src/core/coreircchannel.cpp b/src/core/coreircchannel.cpp index a7e1b6c6..99d18815 100644 --- a/src/core/coreircchannel.cpp +++ b/src/core/coreircchannel.cpp @@ -59,13 +59,6 @@ void CoreIrcChannel::setEncrypted(bool e) if (topic().isEmpty()) return; - QByteArray key = qobject_cast(network())->cipherKey(name()); - if (key.isEmpty()) - return; - - if (!cipher()->setKey(key)) - return; - QByteArray decrypted = cipher()->decryptTopic(topic().toAscii()); setTopic(decodeString(decrypted)); } diff --git a/src/core/corenetwork.cpp b/src/core/corenetwork.cpp index b734312b..101f5276 100644 --- a/src/core/corenetwork.cpp +++ b/src/core/corenetwork.cpp @@ -310,7 +310,7 @@ void CoreNetwork::removeChannelKey(const QString &channel) #ifdef HAVE_QCA2 -Cipher *CoreNetwork::cipher(const QString &target) const +Cipher *CoreNetwork::cipher(const QString &target) { if (target.isEmpty()) return 0; @@ -318,39 +318,51 @@ Cipher *CoreNetwork::cipher(const QString &target) const if (!Cipher::neededFeaturesAvailable()) return 0; - QByteArray key = cipherKey(target); - if (key.isEmpty()) - return 0; - CoreIrcChannel *channel = qobject_cast(ircChannel(target)); if (channel) { - if (channel->cipher()->setKey(key)) - return channel->cipher(); + return channel->cipher(); } - else { - CoreIrcUser *user = qobject_cast(ircUser(target)); - if (user && user->cipher()->setKey(key)) - return user->cipher(); + CoreIrcUser *user = qobject_cast(ircUser(target)); + if (user) { + return user->cipher(); + } else if (!isChannelName(target)) { + return qobject_cast(newIrcUser(target))->cipher(); } return 0; } -QByteArray CoreNetwork::cipherKey(const QString &recipient) const +QByteArray CoreNetwork::cipherKey(const QString &target) const { - return _cipherKeys.value(recipient.toLower(), QByteArray()); + CoreIrcChannel *c = qobject_cast(ircChannel(target)); + if (c) + return c->cipher()->key(); + + CoreIrcUser *u = qobject_cast(ircUser(target)); + if (u) + return u->cipher()->key(); + + return QByteArray(); } -void CoreNetwork::setCipherKey(const QString &recipient, const QByteArray &key) +void CoreNetwork::setCipherKey(const QString &target, const QByteArray &key) { - if (!key.isEmpty()) - _cipherKeys[recipient.toLower()] = key; - else - _cipherKeys.remove(recipient.toLower()); -} + CoreIrcChannel *c = qobject_cast(ircChannel(target)); + if (c) { + c->setEncrypted(c->cipher()->setKey(key)); + return; + } + CoreIrcUser *u = qobject_cast(ircUser(target)); + if (!u && !isChannelName(target)) + u = qobject_cast(newIrcUser(target)); + if (u) { + u->setEncrypted(u->cipher()->setKey(key)); + return; + } +} #endif /* HAVE_QCA2 */ bool CoreNetwork::setAutoWhoDone(const QString &channel) diff --git a/src/core/corenetwork.h b/src/core/corenetwork.h index 47575782..3b31f0de 100644 --- a/src/core/corenetwork.h +++ b/src/core/corenetwork.h @@ -120,7 +120,7 @@ public slots: // Blowfish stuff #ifdef HAVE_QCA2 - Cipher *cipher(const QString &recipient) const; + Cipher *cipher(const QString &recipient); QByteArray cipherKey(const QString &recipient) const; void setCipherKey(const QString &recipient, const QByteArray &key); #endif diff --git a/src/core/corenetworkconfig.h b/src/core/corenetworkconfig.h index d906dcb3..e045697c 100644 --- a/src/core/corenetworkconfig.h +++ b/src/core/corenetworkconfig.h @@ -45,6 +45,7 @@ public slots: virtual inline void requestSetAutoWhoInterval(int interval) { setAutoWhoInterval(interval); } virtual inline void requestSetAutoWhoNickLimit(int nickLimit) { setAutoWhoNickLimit(nickLimit); } virtual inline void requestSetAutoWhoDelay(int delay) { setAutoWhoDelay(delay); } + virtual inline void requestSetStandardCtcp(bool enabled) { setStandardCtcp(enabled); } }; diff --git a/src/core/coresession.cpp b/src/core/coresession.cpp index fb0aad8e..d44cf2b5 100644 --- a/src/core/coresession.cpp +++ b/src/core/coresession.cpp @@ -37,7 +37,7 @@ #include "coreusersettings.h" #include "ctcpparser.h" #include "eventstringifier.h" -#include "internalconnection.h" +#include "internalpeer.h" #include "ircchannel.h" #include "ircparser.h" #include "ircuser.h" @@ -46,7 +46,7 @@ #include "storage.h" #include "util.h" -#include "protocols/legacy/legacyconnection.h" +#include "protocols/legacy/legacypeer.h" class ProcessMessagesEvent : public QEvent { @@ -206,28 +206,28 @@ void CoreSession::restoreSessionState() } -void CoreSession::addClient(RemoteConnection *connection) +void CoreSession::addClient(RemotePeer *peer) { QVariantMap reply; reply["MsgType"] = "SessionInit"; reply["SessionState"] = sessionState(); - connection->writeSocketData(reply); - signalProxy()->addPeer(connection); + peer->writeSocketData(reply); + signalProxy()->addPeer(peer); } -void CoreSession::addClient(InternalConnection *connection) +void CoreSession::addClient(InternalPeer *peer) { - signalProxy()->addPeer(connection); + signalProxy()->addPeer(peer); emit sessionState(sessionState()); } void CoreSession::removeClient(SignalProxy::AbstractPeer *peer) { - RemoteConnection *connection = qobject_cast(peer); - if (connection) - quInfo() << qPrintable(tr("Client")) << connection->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt())); + RemotePeer *p = qobject_cast(peer); + if (p) + quInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt())); } diff --git a/src/core/coresession.h b/src/core/coresession.h index b104631e..fdb952f7 100644 --- a/src/core/coresession.h +++ b/src/core/coresession.h @@ -42,11 +42,11 @@ class CoreSessionEventProcessor; class CtcpParser; class EventManager; class EventStringifier; -class InternalConnection; +class InternalPeer; class IrcParser; class MessageEvent; class NetworkConnection; -class RemoteConnection; +class RemotePeer; struct NetworkInfo; @@ -89,8 +89,8 @@ public: void restoreSessionState(); public slots: - void addClient(RemoteConnection *connection); - void addClient(InternalConnection *connection); + void addClient(RemotePeer *peer); + void addClient(InternalPeer *peer); void msgFromClient(BufferInfo, QString message); diff --git a/src/core/coresessioneventprocessor.cpp b/src/core/coresessioneventprocessor.cpp index c9a7365b..692257a5 100644 --- a/src/core/coresessioneventprocessor.cpp +++ b/src/core/coresessioneventprocessor.cpp @@ -30,6 +30,10 @@ #include "netsplit.h" #include "quassel.h" +#ifdef HAVE_QCA2 +# include "keyevent.h" +#endif + CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session) : BasicHandler("handleCtcp", session), _coreSession(session) @@ -112,14 +116,22 @@ void CoreSessionEventProcessor::processIrcEventAuthenticate(IrcEvent *e) CoreNetwork *net = coreNetwork(e); - QString construct = net->saslAccount(); - construct.append(QChar(QChar::Null)); - construct.append(net->saslAccount()); - construct.append(QChar(QChar::Null)); - construct.append(net->saslPassword()); - QByteArray saslData = QByteArray(construct.toAscii().toBase64()); - saslData.prepend("AUTHENTICATE "); - net->putRawLine(saslData); +#ifdef HAVE_SSL + if (net->identityPtr()->sslCert().isNull()) { +#endif + QString construct = net->saslAccount(); + construct.append(QChar(QChar::Null)); + construct.append(net->saslAccount()); + construct.append(QChar(QChar::Null)); + construct.append(net->saslPassword()); + QByteArray saslData = QByteArray(construct.toAscii().toBase64()); + saslData.prepend("AUTHENTICATE "); + net->putRawLine(saslData); +#ifdef HAVE_SSL + } else { + net->putRawLine("AUTHENTICATE +"); + } +#endif } @@ -129,9 +141,19 @@ void CoreSessionEventProcessor::processIrcEventCap(IrcEvent *e) // additional CAP messages (ls, multi-prefix, et cetera). if (e->params().count() == 3) { - if (e->params().at(2) == "sasl") { + if (e->params().at(2).startsWith("sasl")) { // Freenode (at least) sends "sasl " with a trailing space for some reason! // FIXME use event - coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN")); // Only working with PLAIN atm, blowfish later + // if the current identity has a cert set, use SASL EXTERNAL +#ifdef HAVE_SSL + if (!coreNetwork(e)->identityPtr()->sslCert().isNull()) { + coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE EXTERNAL")); + } else { +#endif + // Only working with PLAIN atm, blowfish later + coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN")); +#ifdef HAVE_SSL + } +#endif } } } @@ -418,6 +440,42 @@ void CoreSessionEventProcessor::processIrcEventTopic(IrcEvent *e) } +#ifdef HAVE_QCA2 +void CoreSessionEventProcessor::processKeyEvent(KeyEvent *e) +{ + if (!Cipher::neededFeaturesAvailable()) { + emit newEvent(new MessageEvent(Message::Error, e->network(), tr("Unable to perform key exchange."), e->prefix(), e->target(), Message::None, e->timestamp())); + return; + } + CoreNetwork *net = qobject_cast(e->network()); + Cipher *c = net->cipher(e->target()); + if (!c) // happens when there is no CoreIrcChannel for the target (i.e. never?) + return; + + if (e->exchangeType() == KeyEvent::Init) { + QByteArray pubKey = c->parseInitKeyX(e->key()); + if (pubKey.isEmpty()) { + emit newEvent(new MessageEvent(Message::Error, e->network(), tr("Unable to parse the DH1080_INIT. Key exchange failed."), e->prefix(), e->target(), Message::None, e->timestamp())); + return; + } else { + net->setCipherKey(e->target(), c->key()); + emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Your key is set and messages will be encrypted."), e->prefix(), e->target(), Message::None, e->timestamp())); + QList p; + p << net->serverEncode(e->target()) << net->serverEncode("DH1080_FINISH ")+pubKey; + net->putCmd("NOTICE", p); + } + } else { + if (c->parseFinishKeyX(e->key())) { + net->setCipherKey(e->target(), c->key()); + emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Your key is set and messages will be encrypted."), e->prefix(), e->target(), Message::None, e->timestamp())); + } else { + emit newEvent(new MessageEvent(Message::Info, e->network(), tr("Failed to parse DH1080_FINISH. Key exchange failed."), e->prefix(), e->target(), Message::None, e->timestamp())); + } + } +} +#endif + + /* RPL_WELCOME */ void CoreSessionEventProcessor::processIrcEvent001(IrcEvent *e) { diff --git a/src/core/coresessioneventprocessor.h b/src/core/coresessioneventprocessor.h index 680917ac..6a163c6c 100644 --- a/src/core/coresessioneventprocessor.h +++ b/src/core/coresessioneventprocessor.h @@ -31,6 +31,10 @@ class IrcEvent; class IrcEventNumeric; class Netsplit; +#ifdef HAVE_QCA2 +class KeyEvent; +#endif + class CoreSessionEventProcessor : public BasicHandler { Q_OBJECT @@ -55,6 +59,9 @@ public: Q_INVOKABLE void processIrcEventQuit(IrcEvent *event); Q_INVOKABLE void lateProcessIrcEventQuit(IrcEvent *event); Q_INVOKABLE void processIrcEventTopic(IrcEvent *event); +#ifdef HAVE_QCA2 + Q_INVOKABLE void processKeyEvent(KeyEvent *event); +#endif Q_INVOKABLE void processIrcEvent001(IrcEvent *event); // RPL_WELCOME Q_INVOKABLE void processIrcEvent005(IrcEvent *event); // RPL_ISUPPORT diff --git a/src/core/coreuserinputhandler.cpp b/src/core/coreuserinputhandler.cpp index 05424a6b..6f721c16 100644 --- a/src/core/coreuserinputhandler.cpp +++ b/src/core/coreuserinputhandler.cpp @@ -207,14 +207,6 @@ void CoreUserInputHandler::handleDelkey(const BufferInfo &bufferInfo, const QStr } network()->setCipherKey(target, QByteArray()); - - if (network()->isChannelName(target) && network()->channels().contains(target)) { - qobject_cast(network()->ircChannel(target))->setEncrypted(false); - } - else if (network()->nicks().contains(target)) { - qobject_cast(network()->ircUser(target))->setEncrypted(false); - } - emit displayMsg(Message::Info, bufferInfo.bufferName(), tr("The key for %1 has been deleted.").arg(target)); #else @@ -226,34 +218,62 @@ void CoreUserInputHandler::handleDelkey(const BufferInfo &bufferInfo, const QStr #endif } +void CoreUserInputHandler::doMode(const BufferInfo &bufferInfo, const QChar& addOrRemove, const QChar& mode, const QString &nicks) +{ + QString m; + bool isNumber; + int maxModes = network()->support("MODES").toInt(&isNumber); + if (!isNumber || maxModes == 0) maxModes = 1; + + QStringList nickList; + if (nicks == "*") { // All users in channel + const QList users = network()->ircChannel(bufferInfo.bufferName())->ircUsers(); + foreach(IrcUser *user, users) { + if ((addOrRemove == '+' && !network()->ircChannel(bufferInfo.bufferName())->userModes(user).contains(mode)) + || (addOrRemove == '-' && network()->ircChannel(bufferInfo.bufferName())->userModes(user).contains(mode))) + nickList.append(user->nick()); + } + } else { + nickList = nicks.split(' ', QString::SkipEmptyParts); + } + + if (nickList.count() == 0) return; + + while (!nickList.isEmpty()) { + int amount = qMin(nickList.count(), maxModes); + QString m = addOrRemove; for(int i = 0; i < amount; i++) m += mode; + QStringList params; + params << bufferInfo.bufferName() << m; + for(int i = 0; i < amount; i++) params << nickList.takeFirst(); + emit putCmd("MODE", serverEncode(params)); + } +} + -void CoreUserInputHandler::handleDeop(const BufferInfo &bufferInfo, const QString &msg) +void CoreUserInputHandler::handleDeop(const BufferInfo &bufferInfo, const QString &nicks) { - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "-"; for (int i = 0; i < nicks.count(); i++) m += 'o'; - QStringList params; - params << bufferInfo.bufferName() << m << nicks; - emit putCmd("MODE", serverEncode(params)); + doMode(bufferInfo, '-', 'o', nicks); } -void CoreUserInputHandler::handleDehalfop(const BufferInfo &bufferInfo, const QString &msg) +void CoreUserInputHandler::handleDehalfop(const BufferInfo &bufferInfo, const QString &nicks) { - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "-"; for (int i = 0; i < nicks.count(); i++) m += 'h'; - QStringList params; - params << bufferInfo.bufferName() << m << nicks; - emit putCmd("MODE", serverEncode(params)); + doMode(bufferInfo, '-', 'h', nicks); } -void CoreUserInputHandler::handleDevoice(const BufferInfo &bufferInfo, const QString &msg) +void CoreUserInputHandler::handleDevoice(const BufferInfo &bufferInfo, const QString &nicks) { - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "-"; for (int i = 0; i < nicks.count(); i++) m += 'v'; - QStringList params; - params << bufferInfo.bufferName() << m << nicks; - emit putCmd("MODE", serverEncode(params)); + doMode(bufferInfo, '-', 'v', nicks); +} + +void CoreUserInputHandler::handleHalfop(const BufferInfo &bufferInfo, const QString &nicks) +{ + doMode(bufferInfo, '+', 'h', nicks); +} + +void CoreUserInputHandler::handleOp(const BufferInfo &bufferInfo, const QString &nicks) { + doMode(bufferInfo, '+', 'o', nicks); } @@ -327,6 +347,50 @@ void CoreUserInputHandler::handleJoin(const BufferInfo &bufferInfo, const QStrin } +void CoreUserInputHandler::handleKeyx(const BufferInfo &bufferInfo, const QString &msg) +{ +#ifdef HAVE_QCA2 + if (!bufferInfo.isValid()) + return; + + if (!Cipher::neededFeaturesAvailable()) + return; + + QStringList parms = msg.split(' ', QString::SkipEmptyParts); + + if (parms.count() == 0 && !bufferInfo.bufferName().isEmpty()) + parms.prepend(bufferInfo.bufferName()); + else if (parms.count() != 1) { + emit displayMsg(Message::Info, bufferInfo.bufferName(), + tr("[usage] /keyx [] Initiates a DH1080 key exchange with the target.")); + return; + } + + QString target = parms.at(0); + + Cipher *cipher = network()->cipher(target); + if (!cipher) // happens when there is no CoreIrcChannel for the target + return; + + QByteArray pubKey = cipher->initKeyExchange(); + if (pubKey.isEmpty()) + emit displayMsg(Message::Error, bufferInfo.bufferName(), tr("Failed to initiate key exchange with %1.").arg(target)); + else { + QList params; + params << serverEncode(target) << serverEncode("DH1080_INIT ") + pubKey; + emit putCmd("NOTICE", params); + emit displayMsg(Message::Info, bufferInfo.bufferName(), tr("Initiated key exchange with %1.").arg(target)); + } +#else + Q_UNUSED(msg) + emit displayMsg(Message::Error, bufferInfo.bufferName(), tr("Error: Setting an encryption key requires Quassel to have been built " + "with support for the Qt Cryptographic Architecture (QCA) library. " + "Contact your distributor about a Quassel package with QCA " + "support, or rebuild Quassel with QCA present.")); +#endif +} + + void CoreUserInputHandler::handleKick(const BufferInfo &bufferInfo, const QString &msg) { QString nick = msg.section(' ', 0, 0, QString::SectionSkipEmpty); @@ -427,25 +491,6 @@ void CoreUserInputHandler::handleNotice(const BufferInfo &bufferInfo, const QStr } -void CoreUserInputHandler::handleHalfop(const BufferInfo &bufferInfo, const QString &msg) -{ - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "+"; for (int i = 0; i < nicks.count(); i++) m += 'h'; - QStringList params; - params << bufferInfo.bufferName() << m << nicks; - emit putCmd("MODE", serverEncode(params)); -} - - -void CoreUserInputHandler::handleOp(const BufferInfo &bufferInfo, const QString &msg) -{ - QStringList nicks = msg.split(' ', QString::SkipEmptyParts); - QString m = "+"; for (int i = 0; i < nicks.count(); i++) m += 'o'; - QStringList params; - params << bufferInfo.bufferName() << m << nicks; - emit putCmd("MODE", serverEncode(params)); -} - void CoreUserInputHandler::handleOper(const BufferInfo &bufferInfo, const QString &msg) { @@ -560,14 +605,8 @@ void CoreUserInputHandler::handleSetkey(const BufferInfo &bufferInfo, const QStr QString target = parms.at(0); QByteArray key = parms.at(1).toLocal8Bit(); - network()->setCipherKey(target, key); - if (network()->isChannelName(target) && network()->channels().contains(target)) - qobject_cast(network()->ircChannel(target))->setEncrypted(true); - else if (network()->nicks().contains(target)) - qobject_cast(network()->ircUser(target))->setEncrypted(true); - emit displayMsg(Message::Info, bufferInfo.bufferName(), tr("The key for %1 has been set.").arg(target)); #else Q_UNUSED(msg) @@ -716,7 +755,7 @@ void CoreUserInputHandler::putPrivmsg(const QByteArray &target, const QByteArray QByteArray crypted = message.left(splitPos); bool isEncrypted = false; #ifdef HAVE_QCA2 - if (cipher && !message.isEmpty()) { + if (cipher && !cipher->key().isEmpty() && !message.isEmpty()) { isEncrypted = cipher->encrypt(crypted); } #endif @@ -797,7 +836,7 @@ QByteArray CoreUserInputHandler::encrypt(const QString &target, const QByteArray return message_; Cipher *cipher = network()->cipher(target); - if (!cipher) + if (!cipher || cipher->key().isEmpty()) return message_; QByteArray message = message_; diff --git a/src/core/coreuserinputhandler.h b/src/core/coreuserinputhandler.h index b6ebac1b..7172fb61 100644 --- a/src/core/coreuserinputhandler.h +++ b/src/core/coreuserinputhandler.h @@ -43,11 +43,12 @@ public slots: void handleUnban(const BufferInfo &bufferInfo, const QString &text); void handleCtcp(const BufferInfo &bufferInfo, const QString &text); void handleDelkey(const BufferInfo &bufferInfo, const QString &text); - void handleDeop(const BufferInfo &bufferInfo, const QString &text); - void handleDehalfop(const BufferInfo &bufferInfo, const QString &text); - void handleDevoice(const BufferInfo &bufferInfo, const QString &text); + void handleDeop(const BufferInfo& bufferInfo, const QString &nicks); + void handleDehalfop(const BufferInfo& bufferInfo, const QString &nicks); + void handleDevoice(const BufferInfo& bufferInfo, const QString &nicks); void handleInvite(const BufferInfo &bufferInfo, const QString &text); void handleJoin(const BufferInfo &bufferInfo, const QString &text); + void handleKeyx(const BufferInfo &bufferInfo, const QString &text); void handleKick(const BufferInfo &bufferInfo, const QString &text); void handleKill(const BufferInfo &bufferInfo, const QString &text); void handleList(const BufferInfo &bufferInfo, const QString &text); @@ -57,8 +58,8 @@ public slots: void handleNick(const BufferInfo &bufferInfo, const QString &text); void handleNotice(const BufferInfo &bufferInfo, const QString &text); void handleOper(const BufferInfo &bufferInfo, const QString &text); - void handleOp(const BufferInfo &bufferInfo, const QString &text); - void handleHalfop(const BufferInfo &bufferInfo, const QString &text); + void handleOp(const BufferInfo& bufferInfo, const QString &nicks); + void handleHalfop(const BufferInfo& bufferInfo, const QString &nicks); void handlePart(const BufferInfo &bufferInfo, const QString &text); void handlePing(const BufferInfo &bufferInfo, const QString &text); void handleQuery(const BufferInfo &bufferInfo, const QString &text); @@ -83,6 +84,7 @@ protected: void timerEvent(QTimerEvent *event); private: + void doMode(const BufferInfo& bufferInfo, const QChar &addOrRemove, const QChar &mode, const QString &nickList); void banOrUnban(const BufferInfo &bufferInfo, const QString &text, bool ban); void putPrivmsg(const QByteArray &target, const QByteArray &message, Cipher *cipher = 0); int lastParamOverrun(const QString &cmd, const QList ¶ms); diff --git a/src/core/ctcpparser.cpp b/src/core/ctcpparser.cpp index cddb6e18..7517db6f 100644 --- a/src/core/ctcpparser.cpp +++ b/src/core/ctcpparser.cpp @@ -20,6 +20,7 @@ #include "ctcpparser.h" +#include "corenetworkconfig.h" #include "coresession.h" #include "ctcpevent.h" #include "messageevent.h" @@ -36,14 +37,24 @@ CtcpParser::CtcpParser(CoreSession *coreSession, QObject *parent) _ctcpMDequoteHash[MQUOTE + 'r'] = QByteArray(1, '\r'); _ctcpMDequoteHash[MQUOTE + MQUOTE] = MQUOTE; - QByteArray XQUOTE = QByteArray("\134"); - _ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE; - _ctcpXDelimDequoteHash[XQUOTE + QByteArray("a")] = XDELIM; + setStandardCtcp(_coreSession->networkConfig()->standardCtcp()); + connect(_coreSession->networkConfig(), SIGNAL(standardCtcpSet(bool)), this, SLOT(setStandardCtcp(bool))); connect(this, SIGNAL(newEvent(Event *)), _coreSession->eventManager(), SLOT(postEvent(Event *))); } +void CtcpParser::setStandardCtcp(bool enabled) +{ + QByteArray XQUOTE = QByteArray("\134"); + if (enabled) + _ctcpXDelimDequoteHash[XQUOTE + XQUOTE] = XQUOTE; + else + _ctcpXDelimDequoteHash.remove(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) { @@ -148,8 +159,6 @@ void CtcpParser::processIrcEventRawPrivmsg(IrcEventRawMessage *event) void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype) { - QByteArray ctcp; - //lowlevel message dequote QByteArray dequotedMessage = lowLevelDequote(e->rawMessage()); @@ -161,6 +170,53 @@ void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype) ? Message::Redirected : Message::None; + if (coreSession()->networkConfig()->standardCtcp()) + parseStandard(e, messagetype, dequotedMessage, ctcptype, flags); + else + parseSimple(e, messagetype, dequotedMessage, ctcptype, flags); +} + + +// only accept CTCPs in their simplest form, i.e. one ctcp, from start to +// end, no text around it; not as per the 'specs', but makes people happier +void CtcpParser::parseSimple(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags) +{ + if (dequotedMessage.count(XDELIM) != 2 || dequotedMessage[0] != '\001' || dequotedMessage[dequotedMessage.count() -1] != '\001') { + displayMsg(e, messagetype, targetDecode(e, dequotedMessage), e->prefix(), e->target(), flags); + } else { + int spacePos = -1; + QString ctcpcmd, ctcpparam; + + QByteArray ctcp = xdelimDequote(dequotedMessage.mid(1, dequotedMessage.count() - 2)); + 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(); + + // 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)) { + QUuid uuid = QUuid::createUuid(); + _replies.insert(uuid, CtcpReply(coreNetwork(e), nickFromMask(e->prefix()))); + CtcpEvent *event = new CtcpEvent(EventManager::CtcpEvent, e->network(), e->prefix(), e->target(), + ctcptype, ctcpcmd, ctcpparam, e->timestamp(), uuid); + emit newEvent(event); + CtcpEvent *flushEvent = new CtcpEvent(EventManager::CtcpEventFlush, e->network(), e->prefix(), e->target(), + ctcptype, "INVALID", QString(), e->timestamp(), uuid); + emit newEvent(flushEvent); + } + } +} + + +void CtcpParser::parseStandard(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags) +{ + QByteArray ctcp; + QList ctcpEvents; QUuid uuid; // needed to group all replies together diff --git a/src/core/ctcpparser.h b/src/core/ctcpparser.h index 255539e1..5847785b 100644 --- a/src/core/ctcpparser.h +++ b/src/core/ctcpparser.h @@ -26,6 +26,7 @@ #include "corenetwork.h" #include "eventmanager.h" #include "ircevent.h" +#include "ctcpevent.h" class CoreSession; class CtcpEvent; @@ -63,6 +64,8 @@ protected: Message::Flags msgFlags = Message::None); void parse(IrcEventRawMessage *event, Message::Type msgType); + void parseSimple(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags); + void parseStandard(IrcEventRawMessage *e, Message::Type messagetype, QByteArray dequotedMessage, CtcpEvent::CtcpType ctcptype, Message::Flags flags); QByteArray lowLevelQuote(const QByteArray &); QByteArray lowLevelDequote(const QByteArray &); @@ -72,6 +75,9 @@ protected: QByteArray pack(const QByteArray &ctcpTag, const QByteArray &message); void packedReply(CoreNetwork *network, const QString &bufname, const QList &replies); +private slots: + void setStandardCtcp(bool enabled); + private: inline QString targetDecode(IrcEventRawMessage *e, const QByteArray &msg) { return coreNetwork(e)->userDecode(e->target(), msg); } diff --git a/src/core/eventstringifier.cpp b/src/core/eventstringifier.cpp index 706abb58..26a2bbe6 100644 --- a/src/core/eventstringifier.cpp +++ b/src/core/eventstringifier.cpp @@ -615,7 +615,7 @@ void EventStringifier::processIrcEvent333(IrcEvent *e) QDateTime topicSetTime = QDateTime::fromTime_t(e->params()[2].toInt()); displayMsg(e, Message::Topic, tr("Topic set by %1 on %2") .arg(e->params()[1], - QLocale().toString(topicSetTime, QLocale().dateTimeFormat()), QString(), channel)); + QLocale().toString(topicSetTime, QLocale().dateTimeFormat())), QString(), channel); } diff --git a/src/core/ircparser.cpp b/src/core/ircparser.cpp index e69336fb..f3db4fce 100644 --- a/src/core/ircparser.cpp +++ b/src/core/ircparser.cpp @@ -28,6 +28,7 @@ #ifdef HAVE_QCA2 # include "cipher.h" +# include "keyevent.h" #endif IrcParser::IrcParser(CoreSession *session) : @@ -58,7 +59,7 @@ QByteArray IrcParser::decrypt(Network *network, const QString &bufferName, const return message; Cipher *cipher = qobject_cast(network)->cipher(bufferName); - if (!cipher) + if (!cipher || cipher->key().isEmpty()) return message; return isTopic ? cipher->decryptTopic(message) : cipher->decrypt(message); @@ -228,7 +229,16 @@ void IrcParser::processNetworkIncoming(NetworkDataEvent *e) if (!net->isChannelName(target)) target = nickFromMask(prefix); } - events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp()); + +#ifdef HAVE_QCA2 + // Handle DH1080 key exchange + if (params[1].startsWith("DH1080_INIT")) { + events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Init, params[1].mid(12)); + } else if (params[1].startsWith("DH1080_FINISH")) { + events << new KeyEvent(EventManager::KeyEvent, net, prefix, target, KeyEvent::Finish, params[1].mid(14)); + } else +#endif + events << new IrcEventRawMessage(EventManager::IrcEventRawNotice, net, params[1], prefix, target, e->timestamp()); } } break; diff --git a/src/core/postgresqlstorage.cpp b/src/core/postgresqlstorage.cpp index d9ba073e..39657046 100644 --- a/src/core/postgresqlstorage.cpp +++ b/src/core/postgresqlstorage.cpp @@ -279,21 +279,26 @@ void PostgreSqlStorage::setUserSetting(UserId userId, const QString &settingName out << data; QSqlDatabase db = logDb(); - QSqlQuery query(db); - query.prepare(queryString("insert_user_setting")); - query.bindValue(":userid", userId.toInt()); - query.bindValue(":settingname", settingName); - query.bindValue(":settingvalue", rawData); - safeExec(query); + QSqlQuery selectQuery(db); + selectQuery.prepare(queryString("select_user_setting")); + selectQuery.bindValue(":userid", userId.toInt()); + selectQuery.bindValue(":settingname", settingName); + safeExec(selectQuery); - if (query.lastError().isValid()) { - QSqlQuery updateQuery(db); - updateQuery.prepare(queryString("update_user_setting")); - updateQuery.bindValue(":userid", userId.toInt()); - updateQuery.bindValue(":settingname", settingName); - updateQuery.bindValue(":settingvalue", rawData); - safeExec(updateQuery); + QString setQueryString; + if (!selectQuery.first()) { + setQueryString = queryString("insert_user_setting"); + } + else { + setQueryString = queryString("update_user_setting"); } + + QSqlQuery setQuery(db); + setQuery.prepare(setQueryString); + setQuery.bindValue(":userid", userId.toInt()); + setQuery.bindValue(":settingname", settingName); + setQuery.bindValue(":settingvalue", rawData); + safeExec(setQuery); } diff --git a/src/core/sessionthread.cpp b/src/core/sessionthread.cpp index 24cba31c..e886db5a 100644 --- a/src/core/sessionthread.cpp +++ b/src/core/sessionthread.cpp @@ -20,8 +20,8 @@ #include "core.h" #include "coresession.h" -#include "internalconnection.h" -#include "remoteconnection.h" +#include "internalpeer.h" +#include "remotepeer.h" #include "sessionthread.h" #include "signalproxy.h" @@ -86,13 +86,13 @@ void SessionThread::addClient(QObject *peer) void SessionThread::addClientToSession(QObject *peer) { - RemoteConnection *connection = qobject_cast(peer); - if (connection) { - addRemoteClientToSession(connection); + RemotePeer *remote = qobject_cast(peer); + if (remote) { + addRemoteClientToSession(remote); return; } - InternalConnection *internal = qobject_cast(peer); + InternalPeer *internal = qobject_cast(peer); if (internal) { addInternalClientToSession(internal); return; @@ -102,27 +102,27 @@ void SessionThread::addClientToSession(QObject *peer) } -void SessionThread::addRemoteClientToSession(RemoteConnection *connection) +void SessionThread::addRemoteClientToSession(RemotePeer *remotePeer) { - connection->setParent(0); - connection->moveToThread(session()->thread()); - emit addRemoteClient(connection); + remotePeer->setParent(0); + remotePeer->moveToThread(session()->thread()); + emit addRemoteClient(remotePeer); } -void SessionThread::addInternalClientToSession(InternalConnection *connection) +void SessionThread::addInternalClientToSession(InternalPeer *internalPeer) { - connection->setParent(0); - connection->moveToThread(session()->thread()); - emit addInternalClient(connection); + internalPeer->setParent(0); + internalPeer->moveToThread(session()->thread()); + emit addInternalClient(internalPeer); } void SessionThread::run() { _session = new CoreSession(user(), _restoreState); - connect(this, SIGNAL(addRemoteClient(RemoteConnection*)), _session, SLOT(addClient(RemoteConnection*))); - connect(this, SIGNAL(addInternalClient(InternalConnection*)), _session, SLOT(addClient(InternalConnection*))); + connect(this, SIGNAL(addRemoteClient(RemotePeer*)), _session, SLOT(addClient(RemotePeer*))); + connect(this, SIGNAL(addInternalClient(InternalPeer*)), _session, SLOT(addClient(InternalPeer*))); connect(_session, SIGNAL(sessionState(QVariant)), Core::instance(), SIGNAL(sessionState(QVariant))); emit initialized(); exec(); diff --git a/src/core/sessionthread.h b/src/core/sessionthread.h index 9639f684..b36b2433 100644 --- a/src/core/sessionthread.h +++ b/src/core/sessionthread.h @@ -27,8 +27,8 @@ #include "types.h" class CoreSession; -class InternalConnection; -class RemoteConnection; +class InternalPeer; +class RemotePeer; class QIODevice; class SessionThread : public QThread @@ -54,8 +54,8 @@ signals: void initialized(); void shutdown(); - void addRemoteClient(RemoteConnection *); - void addInternalClient(InternalConnection *); + void addRemoteClient(RemotePeer *peer); + void addInternalClient(InternalPeer *peer); private: CoreSession *_session; @@ -66,8 +66,8 @@ private: bool isSessionInitialized(); void addClientToSession(QObject *peer); - void addRemoteClientToSession(RemoteConnection *connection); - void addInternalClientToSession(InternalConnection *client); + void addRemoteClientToSession(RemotePeer *remotePeer); + void addInternalClientToSession(InternalPeer *internalPeer); }; diff --git a/src/qtui/CMakeLists.txt b/src/qtui/CMakeLists.txt index 86217b8f..8d8dce05 100644 --- a/src/qtui/CMakeLists.txt +++ b/src/qtui/CMakeLists.txt @@ -182,6 +182,11 @@ if(INDICATEQT_FOUND) include_directories(${INDICATEQT_INCLUDE_DIRS}) endif(INDICATEQT_FOUND) +if(HAVE_NOTIFICATION_CENTER) + set(SOURCES ${SOURCES} osxnotificationbackend.mm) + set(MOC_HDRS ${MOC_HDRS} osxnotificationbackend.h) +endif() + foreach(FORM ${FORMS}) set(FORMPATH ${FORMPATH} ui/${FORM}) endforeach(FORM ${FORMS}) diff --git a/src/qtui/mainwin.cpp b/src/qtui/mainwin.cpp index ac1fd977..bf7cda34 100644 --- a/src/qtui/mainwin.cpp +++ b/src/qtui/mainwin.cpp @@ -108,6 +108,10 @@ #include "indicatornotificationbackend.h" #endif +#ifdef HAVE_NOTIFICATION_CENTER + #include "osxnotificationbackend.h" +#endif + #include "settingspages/aliasessettingspage.h" #include "settingspages/appearancesettingspage.h" #include "settingspages/backlogsettingspage.h" @@ -218,6 +222,10 @@ void MainWin::init() QtUi::registerNotificationBackend(new IndicatorNotificationBackend(this)); #endif +#ifdef HAVE_NOTIFICATION_CENTER + QtUi::registerNotificationBackend(new OSXNotificationBackend(this)); +#endif + // we assume that at this point, all configurable actions are defined! QtUi::loadShortcuts(); diff --git a/src/qtui/monoapplication.cpp b/src/qtui/monoapplication.cpp index 67bee8e1..69ca4482 100644 --- a/src/qtui/monoapplication.cpp +++ b/src/qtui/monoapplication.cpp @@ -24,7 +24,7 @@ #include "core.h" #include "qtui.h" -class InternalConnection; +class InternalPeer; MonolithicApplication::MonolithicApplication(int &argc, char **argv) : QtUiApplication(argc, argv), @@ -70,6 +70,6 @@ void MonolithicApplication::startInternalCore() } Core *core = Core::instance(); CoreConnection *connection = Client::coreConnection(); - connect(connection, SIGNAL(connectToInternalCore(InternalConnection*)), core, SLOT(setupInternalClientSession(InternalConnection*))); + connect(connection, SIGNAL(connectToInternalCore(InternalPeer*)), core, SLOT(setupInternalClientSession(InternalPeer*))); connect(core, SIGNAL(sessionState(QVariant)), connection, SLOT(internalSessionStateReceived(QVariant))); } diff --git a/src/qtui/osxnotificationbackend.h b/src/qtui/osxnotificationbackend.h new file mode 100644 index 00000000..55a8d58e --- /dev/null +++ b/src/qtui/osxnotificationbackend.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2005-2012 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef OSXNOTIFICATIONBACKEND_H_ +#define OSXNOTIFICATIONBACKEND_H_ + +#include "abstractnotificationbackend.h" +#include "settingspage.h" + +class OSXNotificationBackend : public AbstractNotificationBackend +{ + Q_OBJECT + +public: + OSXNotificationBackend(QObject *parent = 0); + + void notify(const Notification &); + void close(uint notificationId); + virtual SettingsPage *createConfigWidget() const; + +private slots: + void enabledChanged(const QVariant &value); + +private: + class ConfigWidget; + + bool _enabled; +}; + +class OSXNotificationBackend::ConfigWidget : public SettingsPage +{ + Q_OBJECT + +public: + ConfigWidget(QWidget *parent = 0); + void save(); + void load(); + bool hasDefaults() const; + void defaults(); + +private slots: + void widgetChanged(); + +private: + QCheckBox *_enabledBox; + bool _enabled; +}; + +#endif // OSXNOTIFICATIONBACKEND_H_ diff --git a/src/qtui/osxnotificationbackend.mm b/src/qtui/osxnotificationbackend.mm new file mode 100644 index 00000000..738ee265 --- /dev/null +++ b/src/qtui/osxnotificationbackend.mm @@ -0,0 +1,126 @@ +/*************************************************************************** + * Copyright (C) 2005-2012 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., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include "clientsettings.h" +#include "osxnotificationbackend.h" + +#include +#include + +#import + +namespace { + +void SendNotificationCenterMessage(NSString* title, NSString* subtitle) { + NSUserNotificationCenter* center = + [NSUserNotificationCenter defaultUserNotificationCenter]; + NSUserNotification* notification = + [[NSUserNotification alloc] init]; + + [notification setTitle: title]; + [notification setSubtitle: subtitle]; + + [center deliverNotification: notification]; + + [notification release]; +} + +} + +OSXNotificationBackend::OSXNotificationBackend(QObject *parent) + : AbstractNotificationBackend(parent), + _enabled(true) +{ + NotificationSettings notificationSettings; + notificationSettings.initAndNotify("OSXNotification/Enabled", this, SLOT(enabledChanged(QVariant)), true); +} + +void OSXNotificationBackend::enabledChanged(const QVariant &value) +{ + _enabled = value.toBool(); +} + +void OSXNotificationBackend::notify(const Notification ¬ification) +{ + if (!_enabled) + { + return; + } + + NSString* message = [[NSString alloc] initWithUTF8String:notification.sender.toUtf8().constData()]; + NSString* summary = [[NSString alloc] initWithUTF8String:notification.message.toUtf8().constData()]; + + SendNotificationCenterMessage(message, summary); + + [message release]; + [summary release]; +} + +void OSXNotificationBackend::close(uint notificationId) +{ +} + +SettingsPage *OSXNotificationBackend::createConfigWidget() const +{ + return new ConfigWidget(); +} + +OSXNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent) + : SettingsPage("Internal", "OSXNotification", parent) +{ + _enabledBox = new QCheckBox(tr("Show OS X notifications")); + connect(_enabledBox, SIGNAL(toggled(bool)), this, SLOT(widgetChanged())); + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(_enabledBox); +} + +void OSXNotificationBackend::ConfigWidget::widgetChanged() +{ + bool changed = (_enabled != _enabledBox->isChecked()); + if (changed != hasChanged()) + setChangedState(changed); +} + +bool OSXNotificationBackend::ConfigWidget::hasDefaults() const +{ + return true; +} + +void OSXNotificationBackend::ConfigWidget::defaults() +{ + _enabledBox->setChecked(true); + widgetChanged(); +} + +void OSXNotificationBackend::ConfigWidget::load() +{ + NotificationSettings s; + _enabled = s.value("OSXNotification/Enabled", false).toBool(); + _enabledBox->setChecked(_enabled); + setChangedState(false); +} + + +void OSXNotificationBackend::ConfigWidget::save() +{ + NotificationSettings s; + s.setValue("OSXNotification/Enabled", _enabledBox->isChecked()); + load(); +} diff --git a/src/qtui/phononnotificationbackend.cpp b/src/qtui/phononnotificationbackend.cpp index 766cf599..bcc7c76d 100644 --- a/src/qtui/phononnotificationbackend.cpp +++ b/src/qtui/phononnotificationbackend.cpp @@ -20,7 +20,8 @@ #include -#include +#include +#include #include "phononnotificationbackend.h" @@ -33,6 +34,7 @@ PhononNotificationBackend::PhononNotificationBackend(QObject *parent) : AbstractNotificationBackend(parent), _media(0) { + _audioAvailable = !Phonon::BackendCapabilities::availableAudioOutputDevices().isEmpty(); NotificationSettings notificationSettings; _enabled = notificationSettings.value("Phonon/Enabled", true).toBool(); createMediaObject(notificationSettings.value("Phonon/AudioFile", QString()).toString()); @@ -51,9 +53,13 @@ PhononNotificationBackend::~PhononNotificationBackend() void PhononNotificationBackend::notify(const Notification ¬ification) { - if (_enabled && _media && (notification.type == Highlight || notification.type == PrivMsg)) { - _media->stop(); - _media->play(); + if (_enabled && (notification.type == Highlight || notification.type == PrivMsg)) { + if (_audioAvailable) { + _media->stop(); + _media->play(); + } + else + QApplication::beep(); } } @@ -92,8 +98,7 @@ void PhononNotificationBackend::createMediaObject(const QString &file) return; } - _media = Phonon::createPlayer(Phonon::NotificationCategory, - Phonon::MediaSource(file)); + _media = Phonon::createPlayer(Phonon::NotificationCategory, Phonon::MediaSource(file)); } @@ -104,6 +109,7 @@ PhononNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent) audioPreview(0) { ui.setupUi(this); + _audioAvailable = !Phonon::BackendCapabilities::availableAudioOutputDevices().isEmpty(); ui.enabled->setIcon(SmallIcon("media-playback-start")); ui.play->setIcon(SmallIcon("media-playback-start")); ui.open->setIcon(SmallIcon("document-open")); @@ -122,12 +128,20 @@ PhononNotificationBackend::ConfigWidget::~ConfigWidget() void PhononNotificationBackend::ConfigWidget::widgetChanged() { - ui.play->setEnabled(ui.enabled->isChecked() && !ui.filename->text().isEmpty()); + if (! _audioAvailable) { + ui.play->setEnabled(ui.enabled->isChecked()); + ui.open->setEnabled(false); + ui.filename->setEnabled(false); + ui.filename->setText(QString()); + } + else { + ui.play->setEnabled(ui.enabled->isChecked() && !ui.filename->text().isEmpty()); - bool changed = (enabled != ui.enabled->isChecked() - || filename != ui.filename->text()); + bool changed = (enabled != ui.enabled->isChecked() || filename != ui.filename->text()); - if (changed != hasChanged()) setChangedState(changed); + if (changed != hasChanged()) + setChangedState(changed); + } } @@ -180,12 +194,15 @@ void PhononNotificationBackend::ConfigWidget::on_open_clicked() void PhononNotificationBackend::ConfigWidget::on_play_clicked() { - if (!ui.filename->text().isEmpty()) { - if (audioPreview) - delete audioPreview; + if (_audioAvailable) { + if (!ui.filename->text().isEmpty()) { + if (audioPreview) + delete audioPreview; - audioPreview = Phonon::createPlayer(Phonon::NotificationCategory, - Phonon::MediaSource(ui.filename->text())); - audioPreview->play(); + audioPreview = Phonon::createPlayer(Phonon::NotificationCategory, Phonon::MediaSource(ui.filename->text())); + audioPreview->play(); + } } + else + QApplication::beep(); } diff --git a/src/qtui/phononnotificationbackend.h b/src/qtui/phononnotificationbackend.h index 1489dc2c..b6ae1bea 100644 --- a/src/qtui/phononnotificationbackend.h +++ b/src/qtui/phononnotificationbackend.h @@ -49,6 +49,7 @@ private: class ConfigWidget; bool _enabled; + bool _audioAvailable; Phonon::MediaObject *_media; }; @@ -75,6 +76,7 @@ private: Ui::PhononNotificationConfigWidget ui; bool enabled; + bool _audioAvailable; QString filename; Phonon::MediaObject *audioPreview; }; diff --git a/src/qtui/settingspages/connectionsettingspage.cpp b/src/qtui/settingspages/connectionsettingspage.cpp index 3d4ac7a3..4fcc70a6 100644 --- a/src/qtui/settingspages/connectionsettingspage.cpp +++ b/src/qtui/settingspages/connectionsettingspage.cpp @@ -85,6 +85,8 @@ QVariant ConnectionSettingsPage::loadAutoWidgetValue(const QString &widgetName) return config->autoWhoNickLimit(); if (widgetName == "autoWhoDelay") return config->autoWhoDelay(); + if (widgetName == "standardCtcp") + return config->standardCtcp(); return SettingsPage::loadAutoWidgetValue(widgetName); } @@ -109,6 +111,8 @@ void ConnectionSettingsPage::saveAutoWidgetValue(const QString &widgetName, cons config->requestSetAutoWhoNickLimit(value.toInt()); else if (widgetName == "autoWhoDelay") config->requestSetAutoWhoDelay(value.toInt()); + else if (widgetName == "standardCtcp") + config->requestSetStandardCtcp(value.toBool()); else SettingsPage::saveAutoWidgetValue(widgetName, value); diff --git a/src/qtui/settingspages/connectionsettingspage.ui b/src/qtui/settingspages/connectionsettingspage.ui index 484454c3..e1ca2480 100644 --- a/src/qtui/settingspages/connectionsettingspage.ui +++ b/src/qtui/settingspages/connectionsettingspage.ui @@ -244,6 +244,16 @@ + + + + Enable standard-compliant CTCP behavior + + + + + + diff --git a/src/qtui/settingspages/networkssettingspage.cpp b/src/qtui/settingspages/networkssettingspage.cpp index bcaab22e..4d66b6f6 100644 --- a/src/qtui/settingspages/networkssettingspage.cpp +++ b/src/qtui/settingspages/networkssettingspage.cpp @@ -35,12 +35,20 @@ NetworksSettingsPage::NetworksSettingsPage(QWidget *parent) : SettingsPage(tr("IRC"), tr("Networks"), parent) +#ifdef HAVE_SSL + , _cid(0) +#endif { ui.setupUi(this); // hide SASL options for older cores if (!(Client::coreFeatures() & Quassel::SaslAuthentication)) ui.sasl->hide(); + if (!(Client::coreFeatures() & Quassel::SaslExternal)) + ui.saslExtInfo->hide(); +#ifndef HAVE_SSL + ui.saslExtInfo->hide(); +#endif // set up icons ui.renameNetwork->setIcon(SmallIcon("edit-rename")); @@ -469,6 +477,20 @@ void NetworksSettingsPage::displayNetwork(NetworkId id) _ignoreWidgetChanges = true; if (id != 0) { NetworkInfo info = networkInfos[id]; + +#ifdef HAVE_SSL + // this is only needed when the core supports SASL EXTERNAL + if (Client::coreFeatures() & Quassel::SaslExternal) { + if (_cid) { + disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated())); + delete _cid; + } + _cid = new CertIdentity(*Client::identity(info.identity), this); + _cid->enableEditSsl(true); + connect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated())); + } +#endif + ui.identityList->setCurrentIndex(ui.identityList->findData(info.identity.toInt())); ui.serverList->clear(); foreach(Network::Server server, info.serverList) { @@ -506,6 +528,12 @@ void NetworksSettingsPage::displayNetwork(NetworkId id) } else { // just clear widgets +#ifdef HAVE_SSL + if (_cid) { + disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated())); + delete _cid; + } +#endif ui.identityList->setCurrentIndex(-1); ui.serverList->clear(); ui.performEdit->clear(); @@ -549,6 +577,26 @@ void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info) } +#ifdef HAVE_SSL +void NetworksSettingsPage::sslUpdated() +{ + if (_cid && !_cid->sslKey().isNull()) { + ui.saslAccount->setDisabled(true); + ui.saslAccountLabel->setDisabled(true); + ui.saslPassword->setDisabled(true); + ui.saslPasswordLabel->setDisabled(true); + ui.saslExtInfo->setHidden(false); + } else { + ui.saslAccount->setDisabled(false); + ui.saslAccountLabel->setDisabled(false); + ui.saslPassword->setDisabled(false); + ui.saslPasswordLabel->setDisabled(false); + ui.saslExtInfo->setHidden(true); + } +} +#endif + + /*** Network list ***/ void NetworksSettingsPage::on_networkList_itemSelectionChanged() diff --git a/src/qtui/settingspages/networkssettingspage.h b/src/qtui/settingspages/networkssettingspage.h index c337325f..ef9f8835 100644 --- a/src/qtui/settingspages/networkssettingspage.h +++ b/src/qtui/settingspages/networkssettingspage.h @@ -25,6 +25,7 @@ #include "network.h" #include "settingspage.h" +#include "clientidentity.h" #include "ui_networkssettingspage.h" #include "ui_networkadddlg.h" @@ -65,6 +66,10 @@ private slots: void clientIdentityRemoved(IdentityId); void clientIdentityUpdated(); +#ifdef HAVE_SSL + void sslUpdated(); +#endif + void on_networkList_itemSelectionChanged(); void on_addNetwork_clicked(); void on_deleteNetwork_clicked(); @@ -86,6 +91,9 @@ private: NetworkId currentId; QHash networkInfos; bool _ignoreWidgetChanges; +#ifdef HAVE_SSL + CertIdentity *_cid; +#endif QPixmap connectedIcon, connectingIcon, disconnectedIcon; diff --git a/src/qtui/settingspages/networkssettingspage.ui b/src/qtui/settingspages/networkssettingspage.ui index 7665e101..7ef574ac 100644 --- a/src/qtui/settingspages/networkssettingspage.ui +++ b/src/qtui/settingspages/networkssettingspage.ui @@ -6,8 +6,8 @@ 0 0 - 515 - 503 + 510 + 505 @@ -607,7 +607,7 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne - + true @@ -617,7 +617,7 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne - + true @@ -629,6 +629,16 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne + + + + <html><head/><body><p><span style=" font-weight:600;">Note:</span> because the identity has an ssl certificate set, SASL EXTERNAL will be used.</p></body></html> + + + true + + + diff --git a/src/uisupport/uistyle.cpp b/src/uisupport/uistyle.cpp index 80464d87..df23a62e 100644 --- a/src/uisupport/uistyle.cpp +++ b/src/uisupport/uistyle.cpp @@ -561,15 +561,43 @@ UiStyle::StyledString UiStyle::styleString(const QString &s_, quint32 baseFormat QString UiStyle::mircToInternal(const QString &mirc_) { - QString mirc = mirc_; - mirc.replace('%', "%%"); // escape % just to be sure - mirc.replace('\t', " "); // tabs break layout, also this is italics in Konversation - mirc.replace('\x02', "%B"); - mirc.replace('\x0f', "%O"); - mirc.replace('\x12', "%R"); - mirc.replace('\x16', "%R"); - mirc.replace('\x1d', "%S"); - mirc.replace('\x1f', "%U"); + QString mirc; + mirc.reserve(mirc_.size()); + foreach (const QChar &c, mirc_) { + if ((c < '\x20' || c == '\x7f') && c != '\x03') { + switch (c.unicode()) { + case '\x02': + mirc += "%B"; + break; + case '\x0f': + mirc += "%O"; + break; + case '\x12': + case '\x16': + mirc += "%R"; + break; + case '\x1d': + mirc += "%S"; + break; + case '\x1f': + mirc += "%U"; + break; + case '\x7f': + mirc += QChar(0x2421); + break; + default: + mirc += QChar(0x2400 + c.unicode()); + } + } else { + if (c == '\t') { + mirc += " "; + continue; + } + if (c == '%') + mirc += c; + mirc += c; + } + } // Now we bring the color codes (\x03) in a sane format that can be parsed more easily later. // %Dcfxx is foreground, %Dcbxx is background color, where xx is a 2 digit dec number denoting the color code.