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)
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
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
<true/>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
+ <key>NSHighResolutionCapable</key>
+ <true/>
<key>NSHumanReadableCopyright</key>
<string>© 2005-2012, Quassel IRC Team</string>
</dict>
#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),
void CoreConnection::reconnectTimeout()
{
- if (!_connection) {
+ if (!_peer) {
CoreConnectionSettings s;
if (_wantReconnect && s.autoReconnect()) {
#ifdef HAVE_KDE
bool CoreConnection::isEncrypted() const
{
- return _connection && _connection->isSecure();
+ return _peer && _peer->isSecure();
}
return false;
if (currentAccount().isInternal())
return true;
- if (_connection->isLocal())
+ if (_peer->isLocal())
return true;
return false;
// 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());
}
_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);
}
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;
}
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
clientInit["UseCompression"] = false;
#endif
- qobject_cast<RemoteConnection *>(_connection)->writeSocketData(clientInit);
+ qobject_cast<RemotePeer *>(_peer)->writeSocketData(clientInit);
}
clientLogin["MsgType"] = "ClientLogin";
clientLogin["User"] = currentAccount().user();
clientLogin["Password"] = currentAccount().password();
- qobject_cast<RemoteConnection*>(_connection)->writeSocketData(clientLogin);
+ qobject_cast<RemotePeer*>(_peer)->writeSocketData(clientLogin);
}
QVariantMap setup;
setup["MsgType"] = "CoreSetupData";
setup["SetupData"] = setupData;
- qobject_cast<RemoteConnection *>(_connection)->writeSocketData(setup);
+ qobject_cast<RemotePeer *>(_peer)->writeSocketData(setup);
}
#endif
#include "coreaccount.h"
-#include "remoteconnection.h"
+#include "remotepeer.h"
#include "types.h"
class CoreAccountModel;
-class InternalConnection;
+class InternalPeer;
class Network;
class SignalProxy;
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());
QVariantMap _coreMsgBuffer;
QPointer<QTcpSocket> _socket;
- QPointer<SignalProxy::AbstractPeer> _connection;
+ QPointer<SignalProxy::AbstractPeer> _peer;
ConnectionState _state;
QTimer _reconnectTimer;
eventmanager.cpp
identity.cpp
ignorelistmanager.cpp
- internalconnection.cpp
+ internalpeer.cpp
ircchannel.cpp
ircevent.cpp
irclisthelper.cpp
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
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}
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)
<< 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
CtcpEvent = 0x00050000,
CtcpEventFlush
+
+#ifdef HAVE_QCA2
+ ,KeyEvent = 0x00060000
+#endif
};
EventManager(QObject *parent = 0);
#include <QCoreApplication>
#include <QThread>
-#include "internalconnection.h"
+#include "internalpeer.h"
using namespace Protocol;
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),
}
-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)
}
-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;
}
-void InternalConnection::setPeer(InternalConnection *peer)
+void InternalPeer::setPeer(InternalPeer *peer)
{
if (_peer) {
qWarning() << Q_FUNC_INFO << "Peer already set, ignoring!";
}
-void InternalConnection::peerDisconnected()
+void InternalPeer::peerDisconnected()
{
disconnect(_peer, 0, this, 0);
_peer = 0;
}
-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!";
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!";
}
-void InternalConnection::customEvent(QEvent *event)
+void InternalPeer::customEvent(QEvent *event)
{
switch ((int)event->type()) {
case SyncMessageEvent: {
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
-#ifndef INTERNALCONNECTION_H
-#define INTERNALCONNECTION_H
+#ifndef INTERNALPEER_H
+#define INTERNALPEER_H
#include <QTcpSocket>
class QEvent;
-class InternalConnection : public SignalProxy::AbstractPeer
+class InternalPeer : public SignalProxy::AbstractPeer
{
Q_OBJECT
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;
private:
SignalProxy *_proxy;
- InternalConnection *_peer;
+ InternalPeer *_peer;
bool _isOpen;
};
--- /dev/null
+/***************************************************************************
+ * 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();
+}
--- /dev/null
+/***************************************************************************
+ * Copyright (C) 2013 by the Quassel Project *
+ * devel@quassel-irc.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) version 3. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
+ ***************************************************************************/
+
+#ifndef KEYEVENT_H
+#define KEYEVENT_H
+
+#include "ircevent.h"
+
+class KeyEvent : public IrcEvent
+{
+public:
+ enum ExchangeType {
+ Init,
+ Finish
+ };
+
+ explicit KeyEvent(EventManager::EventType type, Network *network, const QString &prefix, const QString &target,
+ ExchangeType exchangeType, const QByteArray &key,
+ const QDateTime ×tamp = QDateTime())
+ : IrcEvent(type, network, prefix),
+ _exchangeType(exchangeType),
+ _target(target),
+ _key(key)
+ {
+ setTimestamp(timestamp);
+ }
+
+
+ inline ExchangeType exchangeType() const { return _exchangeType; }
+ inline void setExchangeType(ExchangeType type) { _exchangeType = type; }
+
+ inline QString target() const { return _target; }
+ inline void setTarget(const QString &target) { _target = target; }
+
+ inline QByteArray key() const { return _key; }
+ inline void setKey(const QByteArray &key) { _key = key; }
+
+ static Event *create(EventManager::EventType type, QVariantMap &map, Network *network);
+
+protected:
+ explicit KeyEvent(EventManager::EventType type, QVariantMap &map, Network *network);
+ void toVariantMap(QVariantMap &map) const;
+
+ virtual inline QString className() const { return "KeyEvent"; }
+ virtual inline void debugInfo(QDebug &dbg) const
+ {
+ NetworkEvent::debugInfo(dbg);
+ dbg << ", prefix = " << qPrintable(prefix())
+ << ", target = " << qPrintable(target())
+ << ", exchangetype = " << (exchangeType() == Init ? "init" : "finish")
+ << ", key = " << qPrintable(key());
+ }
+
+
+private:
+ ExchangeType _exchangeType;
+ QString _target;
+ QByteArray _key;
+};
+
+
+#endif
_autoWhoEnabled(true),
_autoWhoInterval(90),
_autoWhoNickLimit(200),
- _autoWhoDelay(5)
+ _autoWhoDelay(5),
+ _standardCtcp(false)
{
}
SYNC(ARG(delay))
emit autoWhoDelaySet(delay);
}
+
+
+void NetworkConfig::setStandardCtcp(bool enabled)
+{
+ if (_standardCtcp == enabled)
+ return;
+
+ _standardCtcp = enabled;
+ SYNC(ARG(enabled))
+ emit standardCtcpSet(enabled);
+}
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);
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);
void autoWhoIntervalSet(int);
// void autoWhoNickLimitSet(int);
void autoWhoDelaySet(int);
+ void standardCtcpSet(bool);
// void setPingTimeoutEnabledRequested(bool);
// void setPingIntervalRequested(int);
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)
{
}
-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!
}
-void LegacyConnection::socketDataAvailable()
+void LegacyPeer::socketDataAvailable()
{
QVariant item;
while (readSocketData(item)) {
}
-bool LegacyConnection::readSocketData(QVariant &item)
+bool LegacyPeer::readSocketData(QVariant &item)
{
if (_blockSize == 0) {
if (socket()->bytesAvailable() < 4)
}
-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!";
}
-void LegacyConnection::handlePackedFunc(const QVariant &packedFunc)
+void LegacyPeer::handlePackedFunc(const QVariant &packedFunc)
{
QVariantList params(packedFunc.toList());
}
-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));
}
* 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
HeartBeatReply
};
- LegacyConnection(QTcpSocket *socket, QObject *parent = 0);
- ~LegacyConnection() {}
+ LegacyPeer(QTcpSocket *socket, QObject *parent = 0);
+ ~LegacyPeer() {}
void setSignalProxy(SignalProxy *proxy);
#include "bufferinfo.h"
#include "types.h"
#include "syncableobject.h"
+#include "logger.h"
Quassel::BuildInfo Quassel::_buildInfo;
AbstractCliParser *Quassel::_cliParser = 0;
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
}
enum Feature {
SynchronizedMarkerLine = 0x0001,
SaslAuthentication = 0x0002,
+ SaslExternal = 0x0004,
- NumFeatures = 0x0002
+ NumFeatures = 0x0004
};
Q_DECLARE_FLAGS(Features, Feature);
# 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),
}
-QString RemoteConnection::description() const
+QString RemotePeer::description() const
{
if (socket())
return socket()->peerAddress().toString();
}
-SignalProxy *RemoteConnection::signalProxy() const
+::SignalProxy *RemotePeer::signalProxy() const
{
return _signalProxy;
}
-void RemoteConnection::setSignalProxy(SignalProxy *proxy)
+void RemotePeer::setSignalProxy(::SignalProxy *proxy)
{
if (proxy == _signalProxy)
return;
}
-void RemoteConnection::changeHeartBeatInterval(int secs)
+void RemotePeer::changeHeartBeatInterval(int secs)
{
if(secs <= 0)
_heartBeatTimer->stop();
}
-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())
}
-bool RemoteConnection::isLocal() const
+bool RemotePeer::isLocal() const
{
if (socket()) {
if (socket()->peerAddress() == QHostAddress::LocalHost || socket()->peerAddress() == QHostAddress::LocalHostIPv6)
}
-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;
}
-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
}
-void RemoteConnection::sendHeartBeat()
+void RemotePeer::sendHeartBeat()
{
if (signalProxy()->maxHeartBeatCount() > 0 && _heartBeatCount >= signalProxy()->maxHeartBeatCount()) {
qWarning() << "Disconnecting peer:" << description()
* 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);
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!";
friend class SignalRelay;
friend class SyncableObject;
- friend class InternalConnection;
- friend class RemoteConnection;
+ friend class InternalPeer;
+ friend class RemotePeer;
};
bool Cipher::setKey(QByteArray key)
{
- if (key.isEmpty())
+ if (key.isEmpty()) {
+ m_key.clear();
return false;
+ }
if (key.mid(0, 4).toLower() == "ecb:")
{
#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>
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;
};
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);
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) {
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;
}
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;
}
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;
}
#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;
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();
}
#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;
else {
reply["MsgType"] = "CoreSetupAck";
}
- connection->writeSocketData(reply);
+ peer->writeSocketData(reply);
}
else if (msg["MsgType"] == "ClientLogin") {
QVariantMap reply;
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);
}
}
}
// 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) {
}
-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;
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));
}
{
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();
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;
else
sessionThread = createSession(uid);
- sessionThread->addClient(coreConnection);
+ sessionThread->addClient(corePeer);
}
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();
}
#include "types.h"
class CoreSession;
-class RemoteConnection;
+class RemotePeer;
struct NetworkInfo;
class SessionThread;
class SignalProxy;
/** \note This method is threadsafe.
*/
void syncStorage();
- void setupInternalClientSession(InternalConnection *clientConnection);
+ void setupInternalClientSession(InternalPeer *clientConnection);
signals:
//! Sent when a BufferInfo is updated in storage.
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);
OidentdConfigGenerator *_oidentdConfigGenerator;
- QHash<RemoteConnection *, QVariantMap> clientInfo;
+ QHash<RemotePeer *, QVariantMap> clientInfo;
QHash<QString, Storage *> _storageBackends;
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));
}
#ifdef HAVE_QCA2
-Cipher *CoreNetwork::cipher(const QString &target) const
+Cipher *CoreNetwork::cipher(const QString &target)
{
if (target.isEmpty())
return 0;
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)
// 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
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); }
};
#include "coreusersettings.h"
#include "ctcpparser.h"
#include "eventstringifier.h"
-#include "internalconnection.h"
+#include "internalpeer.h"
#include "ircchannel.h"
#include "ircparser.h"
#include "ircuser.h"
#include "storage.h"
#include "util.h"
-#include "protocols/legacy/legacyconnection.h"
+#include "protocols/legacy/legacypeer.h"
class ProcessMessagesEvent : public QEvent
{
}
-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()));
}
class CtcpParser;
class EventManager;
class EventStringifier;
-class InternalConnection;
+class InternalPeer;
class IrcParser;
class MessageEvent;
class NetworkConnection;
-class RemoteConnection;
+class RemotePeer;
struct NetworkInfo;
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);
#include "netsplit.h"
#include "quassel.h"
+#ifdef HAVE_QCA2
+# include "keyevent.h"
+#endif
+
CoreSessionEventProcessor::CoreSessionEventProcessor(CoreSession *session)
: BasicHandler("handleCtcp", session),
_coreSession(session)
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
}
// 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
}
}
}
}
+#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)
{
class IrcEventNumeric;
class Netsplit;
+#ifdef HAVE_QCA2
+class KeyEvent;
+#endif
+
class CoreSessionEventProcessor : public BasicHandler
{
Q_OBJECT
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
}
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
#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);
}
}
+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);
}
-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)
{
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)
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
return message_;
Cipher *cipher = network()->cipher(target);
- if (!cipher)
+ if (!cipher || cipher->key().isEmpty())
return message_;
QByteArray message = message_;
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);
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);
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> ¶ms);
#include "ctcpparser.h"
+#include "corenetworkconfig.h"
#include "coresession.h"
#include "ctcpevent.h"
#include "messageevent.h"
_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)
{
void CtcpParser::parse(IrcEventRawMessage *e, Message::Type messagetype)
{
- QByteArray ctcp;
-
//lowlevel message dequote
QByteArray dequotedMessage = lowLevelDequote(e->rawMessage());
? 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
#include "corenetwork.h"
#include "eventmanager.h"
#include "ircevent.h"
+#include "ctcpevent.h"
class CoreSession;
class CtcpEvent;
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 &);
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); }
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);
}
#ifdef HAVE_QCA2
# include "cipher.h"
+# include "keyevent.h"
#endif
IrcParser::IrcParser(CoreSession *session) :
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);
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;
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);
}
#include "core.h"
#include "coresession.h"
-#include "internalconnection.h"
-#include "remoteconnection.h"
+#include "internalpeer.h"
+#include "remotepeer.h"
#include "sessionthread.h"
#include "signalproxy.h"
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;
}
-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();
#include "types.h"
class CoreSession;
-class InternalConnection;
-class RemoteConnection;
+class InternalPeer;
+class RemotePeer;
class QIODevice;
class SessionThread : public QThread
void initialized();
void shutdown();
- void addRemoteClient(RemoteConnection *);
- void addInternalClient(InternalConnection *);
+ void addRemoteClient(RemotePeer *peer);
+ void addInternalClient(InternalPeer *peer);
private:
CoreSession *_session;
bool isSessionInitialized();
void addClientToSession(QObject *peer);
- void addRemoteClientToSession(RemoteConnection *connection);
- void addInternalClientToSession(InternalConnection *client);
+ void addRemoteClientToSession(RemotePeer *remotePeer);
+ void addInternalClientToSession(InternalPeer *internalPeer);
};
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})
#include "indicatornotificationbackend.h"
#endif
+#ifdef HAVE_NOTIFICATION_CENTER
+ #include "osxnotificationbackend.h"
+#endif
+
#include "settingspages/aliasessettingspage.h"
#include "settingspages/appearancesettingspage.h"
#include "settingspages/backlogsettingspage.h"
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();
#include "core.h"
#include "qtui.h"
-class InternalConnection;
+class InternalPeer;
MonolithicApplication::MonolithicApplication(int &argc, char **argv)
: QtUiApplication(argc, argv),
}
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)));
}
--- /dev/null
+/***************************************************************************
+ * 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_
--- /dev/null
+/***************************************************************************
+ * 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 ¬ification)
+{
+ if (!_enabled)
+ {
+ return;
+ }
+
+ NSString* message = [[NSString alloc] initWithUTF8String:notification.sender.toUtf8().constData()];
+ NSString* summary = [[NSString alloc] initWithUTF8String:notification.message.toUtf8().constData()];
+
+ SendNotificationCenterMessage(message, summary);
+
+ [message release];
+ [summary release];
+}
+
+void OSXNotificationBackend::close(uint notificationId)
+{
+}
+
+SettingsPage *OSXNotificationBackend::createConfigWidget() const
+{
+ return new ConfigWidget();
+}
+
+OSXNotificationBackend::ConfigWidget::ConfigWidget(QWidget *parent)
+ : SettingsPage("Internal", "OSXNotification", parent)
+{
+ _enabledBox = new QCheckBox(tr("Show OS X notifications"));
+ connect(_enabledBox, SIGNAL(toggled(bool)), this, SLOT(widgetChanged()));
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ layout->addWidget(_enabledBox);
+}
+
+void OSXNotificationBackend::ConfigWidget::widgetChanged()
+{
+ bool changed = (_enabled != _enabledBox->isChecked());
+ if (changed != hasChanged())
+ setChangedState(changed);
+}
+
+bool OSXNotificationBackend::ConfigWidget::hasDefaults() const
+{
+ return true;
+}
+
+void OSXNotificationBackend::ConfigWidget::defaults()
+{
+ _enabledBox->setChecked(true);
+ widgetChanged();
+}
+
+void OSXNotificationBackend::ConfigWidget::load()
+{
+ NotificationSettings s;
+ _enabled = s.value("OSXNotification/Enabled", false).toBool();
+ _enabledBox->setChecked(_enabled);
+ setChangedState(false);
+}
+
+
+void OSXNotificationBackend::ConfigWidget::save()
+{
+ NotificationSettings s;
+ s.setValue("OSXNotification/Enabled", _enabledBox->isChecked());
+ load();
+}
#include <QFileDialog>
-#include <phonon/mediaobject.h>
+#include <Phonon/MediaObject>
+#include <Phonon/BackendCapabilities>
#include "phononnotificationbackend.h"
: 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());
void PhononNotificationBackend::notify(const Notification ¬ification)
{
- if (_enabled && _media && (notification.type == Highlight || notification.type == PrivMsg)) {
- _media->stop();
- _media->play();
+ if (_enabled && (notification.type == Highlight || notification.type == PrivMsg)) {
+ if (_audioAvailable) {
+ _media->stop();
+ _media->play();
+ }
+ else
+ QApplication::beep();
}
}
return;
}
- _media = Phonon::createPlayer(Phonon::NotificationCategory,
- Phonon::MediaSource(file));
+ _media = Phonon::createPlayer(Phonon::NotificationCategory, Phonon::MediaSource(file));
}
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"));
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);
+ }
}
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();
}
class ConfigWidget;
bool _enabled;
+ bool _audioAvailable;
Phonon::MediaObject *_media;
};
Ui::PhononNotificationConfigWidget ui;
bool enabled;
+ bool _audioAvailable;
QString filename;
Phonon::MediaObject *audioPreview;
};
return config->autoWhoNickLimit();
if (widgetName == "autoWhoDelay")
return config->autoWhoDelay();
+ if (widgetName == "standardCtcp")
+ return config->standardCtcp();
return SettingsPage::loadAutoWidgetValue(widgetName);
}
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);
</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">
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"));
_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) {
}
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();
}
+#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()
#include "network.h"
#include "settingspage.h"
+#include "clientidentity.h"
#include "ui_networkssettingspage.h"
#include "ui_networkadddlg.h"
void clientIdentityRemoved(IdentityId);
void clientIdentityUpdated();
+#ifdef HAVE_SSL
+ void sslUpdated();
+#endif
+
void on_networkList_itemSelectionChanged();
void on_addNetwork_clicked();
void on_deleteNetwork_clicked();
NetworkId currentId;
QHash<NetworkId, NetworkInfo> networkInfos;
bool _ignoreWidgetChanges;
+#ifdef HAVE_SSL
+ CertIdentity *_cid;
+#endif
QPixmap connectedIcon, connectingIcon, disconnectedIcon;
<rect>
<x>0</x>
<y>0</y>
- <width>515</width>
- <height>503</height>
+ <width>510</width>
+ <height>505</height>
</rect>
</property>
<property name="windowTitle">
</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>
</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>
</layout>
</widget>
</item>
+ <item>
+ <widget class="QLabel" name="saslExtInfo">
+ <property name="text">
+ <string><html><head/><body><p><span style=" font-weight:600;">Note:</span> because the identity has an ssl certificate set, SASL EXTERNAL will be used.</p></body></html></string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
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.