Merge pull request #6 from Tucos/genversion
authorManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Feb 2013 22:33:19 +0000 (14:33 -0800)
committerManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Feb 2013 22:33:19 +0000 (14:33 -0800)
Use QCoreApplication::arguments() for genversion

53 files changed:
CMakeLists.txt
scripts/build/Info.plist
src/client/coreconnection.cpp
src/client/coreconnection.h
src/common/CMakeLists.txt
src/common/aliasmanager.cpp
src/common/eventmanager.h
src/common/internalpeer.cpp [moved from src/common/internalconnection.cpp with 80% similarity]
src/common/internalpeer.h [moved from src/common/internalconnection.h with 89% similarity]
src/common/keyevent.cpp [new file with mode: 0644]
src/common/keyevent.h [new file with mode: 0644]
src/common/networkconfig.cpp
src/common/networkconfig.h
src/common/protocols/legacy/legacypeer.cpp [moved from src/common/protocols/legacy/legacyconnection.cpp with 89% similarity]
src/common/protocols/legacy/legacypeer.h [moved from src/common/protocols/legacy/legacyconnection.h with 91% similarity]
src/common/quassel.cpp
src/common/quassel.h
src/common/remotepeer.cpp [moved from src/common/remoteconnection.cpp with 86% similarity]
src/common/remotepeer.h [moved from src/common/remoteconnection.h with 92% similarity]
src/common/signalproxy.h
src/core/cipher.cpp
src/core/core.cpp
src/core/core.h
src/core/coreircchannel.cpp
src/core/corenetwork.cpp
src/core/corenetwork.h
src/core/corenetworkconfig.h
src/core/coresession.cpp
src/core/coresession.h
src/core/coresessioneventprocessor.cpp
src/core/coresessioneventprocessor.h
src/core/coreuserinputhandler.cpp
src/core/coreuserinputhandler.h
src/core/ctcpparser.cpp
src/core/ctcpparser.h
src/core/eventstringifier.cpp
src/core/ircparser.cpp
src/core/postgresqlstorage.cpp
src/core/sessionthread.cpp
src/core/sessionthread.h
src/qtui/CMakeLists.txt
src/qtui/mainwin.cpp
src/qtui/monoapplication.cpp
src/qtui/osxnotificationbackend.h [new file with mode: 0644]
src/qtui/osxnotificationbackend.mm [new file with mode: 0644]
src/qtui/phononnotificationbackend.cpp
src/qtui/phononnotificationbackend.h
src/qtui/settingspages/connectionsettingspage.cpp
src/qtui/settingspages/connectionsettingspage.ui
src/qtui/settingspages/networkssettingspage.cpp
src/qtui/settingspages/networkssettingspage.h
src/qtui/settingspages/networkssettingspage.ui
src/uisupport/uistyle.cpp

index 1bd917c..353511d 100644 (file)
@@ -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
index c0093c6..ccfc721 100644 (file)
@@ -28,6 +28,8 @@
        <true/>
        <key>NSPrincipalClass</key>
        <string>NSApplication</string>
+       <key>NSHighResolutionCapable</key>
+       <true/>
        <key>NSHumanReadableCopyright</key>
        <string>© 2005-2012, Quassel IRC Team</string>
 </dict>
index 8fc5c51..fb553fe 100644 (file)
 #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<RemoteConnection *>(_connection)->writeSocketData(clientInit);
+    qobject_cast<RemotePeer *>(_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<RemoteConnection*>(_connection)->writeSocketData(clientLogin);
+    qobject_cast<RemotePeer*>(_peer)->writeSocketData(clientLogin);
 }
 
 
@@ -809,5 +809,5 @@ void CoreConnection::doCoreSetup(const QVariant &setupData)
     QVariantMap setup;
     setup["MsgType"] = "CoreSetupData";
     setup["SetupData"] = setupData;
-    qobject_cast<RemoteConnection *>(_connection)->writeSocketData(setup);
+    qobject_cast<RemotePeer *>(_peer)->writeSocketData(setup);
 }
index f6ff7ef..836d8cc 100644 (file)
 #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<QTcpSocket> _socket;
-    QPointer<SignalProxy::AbstractPeer> _connection;
+    QPointer<SignalProxy::AbstractPeer> _peer;
     ConnectionState _state;
 
     QTimer _reconnectTimer;
index 3043bb1..c247eb3 100644 (file)
@@ -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)
index 002309d..d4e02a2 100644 (file)
@@ -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
index 3dbd726..edebe61 100644 (file)
@@ -113,6 +113,10 @@ public :
 
         CtcpEvent                   = 0x00050000,
         CtcpEventFlush
+
+#ifdef HAVE_QCA2
+        ,KeyEvent                    = 0x00060000
+#endif
     };
 
     EventManager(QObject *parent = 0);
similarity index 80%
rename from src/common/internalconnection.cpp
rename to src/common/internalpeer.cpp
index 2dda138..15e67ed 100644 (file)
@@ -21,7 +21,7 @@
 #include <QCoreApplication>
 #include <QThread>
 
-#include "internalconnection.h"
+#include "internalpeer.h"
 
 using namespace Protocol;
 
@@ -29,14 +29,14 @@ template<class T>
 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<class T>
-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<class T>
-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: {
similarity index 89%
rename from src/common/internalconnection.h
rename to src/common/internalpeer.h
index dd17f03..4c82ceb 100644 (file)
@@ -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 <QTcpSocket>
 
@@ -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 (file)
index 0000000..afeca21
--- /dev/null
@@ -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<ExchangeType>(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 (file)
index 0000000..0e7b3b8
--- /dev/null
@@ -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 &timestamp = 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
index 17a37b4..066988f 100644 (file)
@@ -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);
+}
index 3d18077..ae121aa 100644 (file)
@@ -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;
 };
 
 
  *   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));
 }
similarity index 91%
rename from src/common/protocols/legacy/legacyconnection.h
rename to src/common/protocols/legacy/legacypeer.h
index 04ac1c3..a3aa178 100644 (file)
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
  ***************************************************************************/
 
-#ifndef LEGACYCONNECTION_H
-#define LEGACYCONNECTION_H
+#ifndef LEGACYPEER_H
+#define LEGACYPEER_H
 
 #include <QDataStream>
 
-#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);
 
index e9763fc..c60f5ec 100644 (file)
@@ -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
 }
index de19313..6089ac0 100644 (file)
@@ -71,8 +71,9 @@ public:
     enum Feature {
         SynchronizedMarkerLine = 0x0001,
         SaslAuthentication = 0x0002,
+        SaslExternal = 0x0004,
 
-        NumFeatures = 0x0002
+        NumFeatures = 0x0004
     };
     Q_DECLARE_FLAGS(Features, Feature);
 
similarity index 86%
rename from src/common/remoteconnection.cpp
rename to src/common/remotepeer.cpp
index c67d3c7..e33f56a 100644 (file)
 #  include <QSslSocket>
 #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()
similarity index 92%
rename from src/common/remoteconnection.h
rename to src/common/remotepeer.h
index 6d12d70..e41a6a3 100644 (file)
@@ -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 <QDateTime>
 #include <QTcpSocket>
 
 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<class T> 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!";
index 7f70f7e..d446fef 100644 (file)
@@ -168,8 +168,8 @@ private:
 
     friend class SignalRelay;
     friend class SyncableObject;
-    friend class InternalConnection;
-    friend class RemoteConnection;
+    friend class InternalPeer;
+    friend class RemotePeer;
 };
 
 
index 5ca3129..15a986b 100644 (file)
@@ -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:")
     {
index e7c56e5..4413211 100644 (file)
 #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 <QFile>
@@ -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<RemoteConnection *>(sender());
-    if (!connection) {
+    RemotePeer *peer = qobject_cast<RemotePeer *>(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("<b>Your Quassel Client is too old!</b><br>"
                                 "This core needs at least client/core protocol version %1.<br>"
                                 "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<SslServer *>(&_server);
-        QSslSocket *sslSocket = qobject_cast<QSslSocket *>(connection->socket());
+        QSslSocket *sslSocket = qobject_cast<QSslSocket *>(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<QSslError> &)), SLOT(sslErrors(const QList<QSslError> &)));
             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("<b>Client not initialized!</b><br>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("<b>Invalid username or password!</b><br>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<RemoteConnection *>(sender());
-    Q_ASSERT(connection);
+    RemotePeer *peer = qobject_cast<RemotePeer *>(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<AddClientEvent *>(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<QSslError> &errors)
 
 void Core::socketError(QAbstractSocket::SocketError err)
 {
-    RemoteConnection *connection = qobject_cast<RemoteConnection *>(sender());
-    if (connection && err != QAbstractSocket::RemoteHostClosedError)
-        qWarning() << "Core::socketError()" << connection->socket() << err << connection->socket()->errorString();
+    RemotePeer *peer = qobject_cast<RemotePeer *>(sender());
+    if (peer && err != QAbstractSocket::RemoteHostClosedError)
+        qWarning() << "Core::socketError()" << peer->socket() << err << peer->socket()->errorString();
 }
 
 
index dfecbe0..ebe8061 100644 (file)
@@ -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<RemoteConnection *, QVariantMap> clientInfo;
+    QHash<RemotePeer *, QVariantMap> clientInfo;
 
     QHash<QString, Storage *> _storageBackends;
 
index a7e1b6c..99d1881 100644 (file)
@@ -59,13 +59,6 @@ void CoreIrcChannel::setEncrypted(bool e)
         if (topic().isEmpty())
             return;
 
-        QByteArray key = qobject_cast<CoreNetwork *>(network())->cipherKey(name());
-        if (key.isEmpty())
-            return;
-
-        if (!cipher()->setKey(key))
-            return;
-
         QByteArray decrypted = cipher()->decryptTopic(topic().toAscii());
         setTopic(decodeString(decrypted));
     }
index b734312..101f527 100644 (file)
@@ -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<CoreIrcChannel *>(ircChannel(target));
     if (channel) {
-        if (channel->cipher()->setKey(key))
-            return channel->cipher();
+        return channel->cipher();
     }
-    else {
-        CoreIrcUser *user = qobject_cast<CoreIrcUser *>(ircUser(target));
-        if (user && user->cipher()->setKey(key))
-            return user->cipher();
+    CoreIrcUser *user = qobject_cast<CoreIrcUser *>(ircUser(target));
+    if (user) {
+        return user->cipher();
+    } else if (!isChannelName(target)) {
+        return qobject_cast<CoreIrcUser*>(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<CoreIrcChannel*>(ircChannel(target));
+    if (c)
+        return c->cipher()->key();
+
+    CoreIrcUser *u = qobject_cast<CoreIrcUser*>(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<CoreIrcChannel*>(ircChannel(target));
+    if (c) {
+        c->setEncrypted(c->cipher()->setKey(key));
+        return;
+    }
 
+    CoreIrcUser *u = qobject_cast<CoreIrcUser*>(ircUser(target));
+    if (!u && !isChannelName(target))
+        u = qobject_cast<CoreIrcUser*>(newIrcUser(target));
 
+    if (u) {
+        u->setEncrypted(u->cipher()->setKey(key));
+        return;
+    }
+}
 #endif /* HAVE_QCA2 */
 
 bool CoreNetwork::setAutoWhoDone(const QString &channel)
index 4757578..3b31f0d 100644 (file)
@@ -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
index d906dcb..e045697 100644 (file)
@@ -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); }
 };
 
 
index fb0aad8..d44cf2b 100644 (file)
@@ -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<RemoteConnection *>(peer);
-    if (connection)
-        quInfo() << qPrintable(tr("Client")) << connection->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
+    RemotePeer *p = qobject_cast<RemotePeer *>(peer);
+    if (p)
+        quInfo() << qPrintable(tr("Client")) << p->description() << qPrintable(tr("disconnected (UserId: %1).").arg(user().toInt()));
 }
 
 
index b104631..fdb952f 100644 (file)
@@ -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);
 
index c9a7365..692257a 100644 (file)
 #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<CoreNetwork*>(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<QByteArray> 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)
 {
index 680917a..6a163c6 100644 (file)
@@ -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
index 05424a6..6f721c1 100644 (file)
@@ -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<CoreIrcChannel *>(network()->ircChannel(target))->setEncrypted(false);
-    }
-    else if (network()->nicks().contains(target)) {
-        qobject_cast<CoreIrcUser *>(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<IrcUser*> 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 [<nick|channel>] 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<QByteArray> 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<CoreIrcChannel *>(network()->ircChannel(target))->setEncrypted(true);
-    else if (network()->nicks().contains(target))
-        qobject_cast<CoreIrcUser *>(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_;
index b6ebac1..7172fb6 100644 (file)
@@ -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<QByteArray> &params);
index cddb6e1..7517db6 100644 (file)
@@ -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<CtcpEvent *> ctcpEvents;
     QUuid uuid; // needed to group all replies together
 
index 255539e..5847785 100644 (file)
@@ -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<QByteArray> &replies);
 
+private slots:
+    void setStandardCtcp(bool enabled);
+
 private:
     inline QString targetDecode(IrcEventRawMessage *e, const QByteArray &msg) { return coreNetwork(e)->userDecode(e->target(), msg); }
 
index 706abb5..26a2bbe 100644 (file)
@@ -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);
 }
 
 
index e69336f..f3db4fc 100644 (file)
@@ -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<CoreNetwork *>(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;
index d9ba073..3965704 100644 (file)
@@ -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);
 }
 
 
index 24cba31..e886db5 100644 (file)
@@ -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<RemoteConnection *>(peer);
-    if (connection) {
-        addRemoteClientToSession(connection);
+    RemotePeer *remote = qobject_cast<RemotePeer *>(peer);
+    if (remote) {
+        addRemoteClientToSession(remote);
         return;
     }
 
-    InternalConnection *internal = qobject_cast<InternalConnection *>(peer);
+    InternalPeer *internal = qobject_cast<InternalPeer *>(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();
index 9639f68..b36b243 100644 (file)
@@ -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);
 };
 
 
index 86217b8..8d8dce0 100644 (file)
@@ -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})
index ac1fd97..bf7cda3 100644 (file)
   #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();
 
index 67bee8e..69ca448 100644 (file)
@@ -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 (file)
index 0000000..55a8d58
--- /dev/null
@@ -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 (file)
index 0000000..738ee26
--- /dev/null
@@ -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 <QCheckBox>
+#include <QHBoxLayout>
+
+#import <Foundation/NSUserNotification.h>
+
+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 &notification)
+{
+    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();
+}
index 766cf59..bcc7c76 100644 (file)
@@ -20,7 +20,8 @@
 
 #include <QFileDialog>
 
-#include <phonon/mediaobject.h>
+#include <Phonon/MediaObject>
+#include <Phonon/BackendCapabilities>
 
 #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 &notification)
 {
-    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();
 }
index 1489dc2..b6ae1be 100644 (file)
@@ -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;
 };
index 3d4ac7a..4fcc70a 100644 (file)
@@ -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);
index 484454c..e1ca248 100644 (file)
      </layout>
     </widget>
    </item>
+   <item>
+    <widget class="QCheckBox" name="standardCtcp">
+     <property name="text">
+      <string>Enable standard-compliant CTCP behavior</string>
+     </property>
+     <property name="settingsKey" stdset="0">
+      <string notr="true" />
+     </property>
+    </widget>
+   </item>
    <item>
     <spacer name="verticalSpacer">
      <property name="orientation">
index bcaab22..4d66b6f 100644 (file)
 
 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()
index c337325..ef9f883 100644 (file)
@@ -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<NetworkId, NetworkInfo> networkInfos;
     bool _ignoreWidgetChanges;
+#ifdef HAVE_SSL
+    CertIdentity *_cid;
+#endif
 
     QPixmap connectedIcon, connectingIcon, disconnectedIcon;
 
index 7665e10..7ef574a 100644 (file)
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>515</width>
-    <height>503</height>
+    <width>510</width>
+    <height>505</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -607,7 +607,7 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
               </widget>
              </item>
              <item row="1" column="0">
-              <widget class="QLabel" name="label_11">
+              <widget class="QLabel" name="saslPasswordLabel">
                <property name="enabled">
                 <bool>true</bool>
                </property>
@@ -617,7 +617,7 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
               </widget>
              </item>
              <item row="0" column="0">
-              <widget class="QLabel" name="label_10">
+              <widget class="QLabel" name="saslAccountLabel">
                <property name="enabled">
                 <bool>true</bool>
                </property>
@@ -629,6 +629,16 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
             </layout>
            </widget>
           </item>
+          <item>
+           <widget class="QLabel" name="saslExtInfo">
+            <property name="text">
+             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Note:&lt;/span&gt; because the identity has an ssl certificate set, SASL EXTERNAL will be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
           <item>
            <spacer name="verticalSpacer_2">
             <property name="orientation">
index 80464d8..df23a62 100644 (file)
@@ -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.