diff options
| author | Jeremy Lainé <jeremy.laine@m4x.org> | 2012-02-08 12:33:41 +0000 |
|---|---|---|
| committer | Jeremy Lainé <jeremy.laine@m4x.org> | 2012-02-08 12:33:41 +0000 |
| commit | 21acd67e9b65bea87902032b12709675905aa922 (patch) | |
| tree | ed5ae9066b10400c4fe6e67dfaf2f4c37a09c32e /src/client/QXmppClient.cpp | |
| parent | cea7ae1e702b82d2d0d0a851de1aae58270b14f6 (diff) | |
| download | qxmpp-21acd67e9b65bea87902032b12709675905aa922.tar.gz | |
start moving client-specific code
Diffstat (limited to 'src/client/QXmppClient.cpp')
| -rw-r--r-- | src/client/QXmppClient.cpp | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/src/client/QXmppClient.cpp b/src/client/QXmppClient.cpp new file mode 100644 index 00000000..3dd93d07 --- /dev/null +++ b/src/client/QXmppClient.cpp @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2008-2011 The QXmpp developers + * + * Author: + * Manjeet Dahiya + * + * Source: + * http://code.google.com/p/qxmpp + * + * This file is a part of QXmpp library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + */ + +#include <QSslSocket> + +#include "QXmppClient.h" +#include "QXmppClientExtension.h" +#include "QXmppConstants.h" +#include "QXmppLogger.h" +#include "QXmppOutgoingClient.h" +#include "QXmppMessage.h" +#include "QXmppUtils.h" + +#include "QXmppReconnectionManager.h" +#include "QXmppRosterManager.h" +#include "QXmppVCardManager.h" +#include "QXmppVersionManager.h" +#include "QXmppEntityTimeManager.h" +#include "QXmppDiscoveryManager.h" +#include "QXmppDiscoveryIq.h" + +class QXmppClientPrivate +{ +public: + QXmppClientPrivate(QXmppClient *qq); + + QXmppPresence clientPresence; ///< Current presence of the client + QList<QXmppClientExtension*> extensions; + QXmppLogger *logger; + QXmppOutgoingClient *stream; ///< Pointer to the XMPP stream + + QXmppReconnectionManager *reconnectionManager; ///< Pointer to the reconnection manager + QXmppRosterManager *rosterManager; ///< Pointer to the roster manager + QXmppVCardManager *vCardManager; ///< Pointer to the vCard manager + QXmppVersionManager *versionManager; ///< Pointer to the version manager + + void addProperCapability(QXmppPresence& presence); + +private: + QXmppClient *q; +}; + +QXmppClientPrivate::QXmppClientPrivate(QXmppClient *qq) + : clientPresence(QXmppPresence::Available), + logger(0), + stream(0), + reconnectionManager(0), + rosterManager(0), + vCardManager(0), + versionManager(0), + q(qq) +{ +} + +void QXmppClientPrivate::addProperCapability(QXmppPresence& presence) +{ + QXmppDiscoveryManager* ext = q->findExtension<QXmppDiscoveryManager>(); + if(ext) { + presence.setCapabilityHash("sha-1"); + presence.setCapabilityNode(ext->clientCapabilitiesNode()); + presence.setCapabilityVer(ext->capabilities().verificationString()); + } +} + +/// \mainpage +/// +/// QXmpp is a cross-platform C++ XMPP client library based on the Qt +/// framework. It tries to use Qt's programming conventions in order to ease +/// the learning curve for new programmers. +/// +/// QXmpp based clients are built using QXmppClient instances which handle the +/// establishment of the XMPP connection and provide a number of high-level +/// "managers" to perform specific tasks. You can write your own managers to +/// extend QXmpp by subclassing QXmppClientExtension. +/// +/// <B>Main Class:</B> +/// - QXmppClient +/// +/// <B>Managers to perform specific tasks:</B> +/// - QXmppRosterManager +/// - QXmppVCardManager +/// - QXmppTransferManager +/// - QXmppMucManager +/// - QXmppCallManager +/// - QXmppArchiveManager +/// - QXmppVersionManager +/// - QXmppDiscoveryManager +/// - QXmppEntityTimeManager +/// +/// <B>XMPP stanzas:</B> If you are interested in a more low-level API, you can refer to these +/// classes. +/// - QXmppIq +/// - QXmppMessage +/// - QXmppPresence +/// +/// <BR><BR> +/// <B>Project Details:</B> +/// +/// Project Page: http://code.google.com/p/qxmpp/ +/// <BR> +/// Report Issues: http://code.google.com/p/qxmpp/issues/ +/// <BR> +/// New Releases: http://code.google.com/p/qxmpp/downloads/ +/// + +/// Creates a QXmppClient object. +/// \param parent is passed to the QObject's constructor. +/// The default value is 0. + +QXmppClient::QXmppClient(QObject *parent) + : QXmppLoggable(parent), + d(new QXmppClientPrivate(this)) +{ + bool check; + Q_UNUSED(check); + + d->stream = new QXmppOutgoingClient(this); + d->addProperCapability(d->clientPresence); + + check = connect(d->stream, SIGNAL(elementReceived(QDomElement,bool&)), + this, SLOT(_q_elementReceived(QDomElement,bool&))); + Q_ASSERT(check); + + check = connect(d->stream, SIGNAL(messageReceived(QXmppMessage)), + this, SIGNAL(messageReceived(QXmppMessage))); + Q_ASSERT(check); + + check = connect(d->stream, SIGNAL(presenceReceived(QXmppPresence)), + this, SIGNAL(presenceReceived(QXmppPresence))); + Q_ASSERT(check); + + check = connect(d->stream, SIGNAL(iqReceived(QXmppIq)), + this, SIGNAL(iqReceived(QXmppIq))); + Q_ASSERT(check); + + check = connect(d->stream->socket(), SIGNAL(stateChanged(QAbstractSocket::SocketState)), + this, SLOT(_q_socketStateChanged(QAbstractSocket::SocketState))); + Q_ASSERT(check); + + check = connect(d->stream, SIGNAL(connected()), + this, SLOT(_q_streamConnected())); + Q_ASSERT(check); + + check = connect(d->stream, SIGNAL(disconnected()), + this, SLOT(_q_streamDisconnected())); + Q_ASSERT(check); + + check = connect(d->stream, SIGNAL(error(QXmppClient::Error)), + this, SIGNAL(error(QXmppClient::Error))); + Q_ASSERT(check); + + check = setReconnectionManager(new QXmppReconnectionManager(this)); + Q_ASSERT(check); + + // logging + setLogger(QXmppLogger::getLogger()); + + // create managers + // TODO move manager references to d->extensions + d->rosterManager = new QXmppRosterManager(this); + addExtension(d->rosterManager); + + d->vCardManager = new QXmppVCardManager; + addExtension(d->vCardManager); + + d->versionManager = new QXmppVersionManager; + addExtension(d->versionManager); + + addExtension(new QXmppEntityTimeManager()); + + QXmppDiscoveryManager *discoveryManager = new QXmppDiscoveryManager; + addExtension(discoveryManager); + + // obsolete signal + check = connect(discoveryManager, SIGNAL(infoReceived(QXmppDiscoveryIq)), + this, SIGNAL(discoveryIqReceived(QXmppDiscoveryIq))); + Q_ASSERT(check); + + check = connect(discoveryManager, SIGNAL(itemsReceived(QXmppDiscoveryIq)), + this, SIGNAL(discoveryIqReceived(QXmppDiscoveryIq))); + Q_ASSERT(check); +} + +/// Destructor, destroys the QXmppClient object. +/// + +QXmppClient::~QXmppClient() +{ + delete d; +} + +/// Registers a new extension with the client. +/// +/// \param extension + +bool QXmppClient::addExtension(QXmppClientExtension* extension) +{ + if (d->extensions.contains(extension)) + { + qWarning("Cannot add extension, it has already been added"); + return false; + } + + extension->setParent(this); + extension->setClient(this); + d->extensions << extension; + return true; +} + +/// Unregisters the given extension from the client. If the extension +/// is found, it will be destroyed. +/// +/// \param extension + +bool QXmppClient::removeExtension(QXmppClientExtension* extension) +{ + if (d->extensions.contains(extension)) + { + d->extensions.removeAll(extension); + delete extension; + return true; + } else { + qWarning("Cannot remove extension, it was never added"); + return false; + } +} + +/// Returns a list containing all the client's extensions. +/// + +QList<QXmppClientExtension*> QXmppClient::extensions() +{ + return d->extensions; +} + +/// Returns a modifiable reference to the current configuration of QXmppClient. +/// \return Reference to the QXmppClient's configuration for the connection. + +QXmppConfiguration& QXmppClient::configuration() +{ + return d->stream->configuration(); +} + +/// Attempts to connect to the XMPP server. Server details and other configurations +/// are specified using the config parameter. Use signals connected(), error(QXmppClient::Error) +/// and disconnected() to know the status of the connection. +/// \param config Specifies the configuration object for connecting the XMPP server. +/// This contains the host name, user, password etc. See QXmppConfiguration for details. +/// \param initialPresence The initial presence which will be set for this user +/// after establishing the session. The default value is QXmppPresence::Available + +void QXmppClient::connectToServer(const QXmppConfiguration& config, + const QXmppPresence& initialPresence) +{ + d->stream->configuration() = config; + if(!config.autoReconnectionEnabled()) + { + delete d->reconnectionManager; + d->reconnectionManager = 0; + } + + d->clientPresence = initialPresence; + d->addProperCapability(d->clientPresence); + + d->stream->connectToHost(); +} + +/// Overloaded function to simply connect to an XMPP server with a JID and password. +/// +/// \param jid JID for the account. +/// \param password Password for the account. + +void QXmppClient::connectToServer(const QString &jid, const QString &password) +{ + QXmppConfiguration config; + config.setJid(jid); + config.setPassword(password); + connectToServer(config); +} + +/// After successfully connecting to the server use this function to send +/// stanzas to the server. This function can solely be used to send various kind +/// of stanzas to the server. QXmppPacket is a parent class of all the stanzas +/// QXmppMessage, QXmppPresence, QXmppIq, QXmppBind, QXmppRosterIq, QXmppSession +/// and QXmppVCard. +/// +/// \return Returns true if the packet was sent, false otherwise. +/// +/// Following code snippet illustrates how to send a message using this function: +/// \code +/// QXmppMessage message(from, to, message); +/// client.sendPacket(message); +/// \endcode +/// +/// \param packet A valid XMPP stanza. It can be an iq, a message or a presence stanza. +/// + +bool QXmppClient::sendPacket(const QXmppPacket& packet) +{ + return d->stream->sendPacket(packet); +} + +/// Disconnects the client and the current presence of client changes to +/// QXmppPresence::Unavailable and status text changes to "Logged out". +/// +/// \note Make sure that the clientPresence is changed to +/// QXmppPresence::Available, if you are again calling connectToServer() after +/// calling the disconnectFromServer() function. +/// + +void QXmppClient::disconnectFromServer() +{ + d->clientPresence.setType(QXmppPresence::Unavailable); + d->clientPresence.status().setType(QXmppPresence::Status::Offline); + d->clientPresence.status().setStatusText("Logged out"); + if (d->stream->isConnected()) + { + sendPacket(d->clientPresence); + } + d->stream->disconnectFromHost(); +} + +/// Returns true if the client is connected to the XMPP server. +/// + +bool QXmppClient::isConnected() const +{ + return d->stream->isConnected(); +} + +/// Returns the reference to QXmppRosterManager object of the client. +/// \return Reference to the roster object of the connected client. Use this to +/// get the list of friends in the roster and their presence information. +/// + +QXmppRosterManager& QXmppClient::rosterManager() +{ + return *d->rosterManager; +} + +/// Utility function to send message to all the resources associated with the +/// specified bareJid. If there are no resources available, that is the contact +/// is offline or not present in the roster, it will still send a message to +/// the bareJid. +/// +/// \param bareJid bareJid of the receiving entity +/// \param message Message string to be sent. + +void QXmppClient::sendMessage(const QString& bareJid, const QString& message) +{ + QStringList resources = rosterManager().getResources(bareJid); + if(!resources.isEmpty()) + { + for(int i = 0; i < resources.size(); ++i) + { + sendPacket(QXmppMessage("", bareJid + "/" + resources.at(i), message)); + } + } + else + { + sendPacket(QXmppMessage("", bareJid, message)); + } +} + +/// Returns the client's current state. + +QXmppClient::State QXmppClient::state() const +{ + if (d->stream->isConnected()) + return QXmppClient::ConnectedState; + else if (d->stream->socket()->state() != QAbstractSocket::UnconnectedState && + d->stream->socket()->state() != QAbstractSocket::ClosingState) + return QXmppClient::ConnectingState; + else + return QXmppClient::DisconnectedState; +} + +/// Returns the client's current presence. +/// + +QXmppPresence QXmppClient::clientPresence() const +{ + return d->clientPresence; +} + +/// Changes the presence of the connected client. +/// +/// The connection to the server will be updated accordingly: +/// +/// \li If the presence type is QXmppPresence::Unavailable, the connection +/// to the server will be closed. +/// +/// \li Otherwise, the connection to the server will be established +/// as needed. +/// +/// \param presence QXmppPresence object +/// + +void QXmppClient::setClientPresence(const QXmppPresence& presence) +{ + d->clientPresence = presence; + d->addProperCapability(d->clientPresence); + + if (presence.type() == QXmppPresence::Unavailable) + { + // NOTE: we can't call disconnect() because it alters + // the client presence + if (d->stream->isConnected()) + { + sendPacket(d->clientPresence); + d->stream->disconnectFromHost(); + } + } + else if (d->stream->isConnected()) + sendPacket(d->clientPresence); + else + connectToServer(d->stream->configuration(), presence); +} + +/// Function to get reconnection manager. By default there exists a reconnection +/// manager. See QXmppReconnectionManager for more details of the reconnection +/// mechanism. +/// +/// \return Pointer to QXmppReconnectionManager +/// + +QXmppReconnectionManager* QXmppClient::reconnectionManager() +{ + return d->reconnectionManager; +} + +/// Sets the user defined reconnection manager. +/// +/// \return true if all the signal-slot connections are made correctly. +/// + +bool QXmppClient::setReconnectionManager(QXmppReconnectionManager* + reconnectionManager) +{ + if(!reconnectionManager) + return false; + + if(d->reconnectionManager) + delete d->reconnectionManager; + + d->reconnectionManager = reconnectionManager; + + bool check = connect(this, SIGNAL(connected()), d->reconnectionManager, + SLOT(connected())); + Q_ASSERT(check); + if(!check) + return false; + + check = connect(this, SIGNAL(error(QXmppClient::Error)), + d->reconnectionManager, SLOT(error(QXmppClient::Error))); + Q_ASSERT(check); + if(!check) + return false; + + return true; +} + +/// Returns the socket error if error() is QXmppClient::SocketError. +/// + +QAbstractSocket::SocketError QXmppClient::socketError() +{ + return d->stream->socket()->error(); +} + +/// Returns the XMPP stream error if QXmppClient::Error is QXmppClient::XmppStreamError. +/// + +QXmppStanza::Error::Condition QXmppClient::xmppStreamError() +{ + return d->stream->xmppStreamError(); +} + +/// Returns the reference to QXmppVCardManager, implementation of XEP-0054. +/// http://xmpp.org/extensions/xep-0054.html +/// + +QXmppVCardManager& QXmppClient::vCardManager() +{ + return *d->vCardManager; +} + +/// Returns the reference to QXmppVersionManager, implementation of XEP-0092. +/// http://xmpp.org/extensions/xep-0092.html +/// + +QXmppVersionManager& QXmppClient::versionManager() +{ + return *d->versionManager; +} + +/// Give extensions a chance to handle incoming stanzas. +/// +/// \param element +/// \param handled + +void QXmppClient::_q_elementReceived(const QDomElement &element, bool &handled) +{ + foreach (QXmppClientExtension *extension, d->extensions) + { + if (extension->handleStanza(element)) + { + handled = true; + return; + } + } +} + +void QXmppClient::_q_socketStateChanged(QAbstractSocket::SocketState socketState) +{ + Q_UNUSED(socketState); + emit stateChanged(state()); +} + +/// At connection establishment, send initial presence. + +void QXmppClient::_q_streamConnected() +{ + // notify managers + emit connected(); + emit stateChanged(QXmppClient::ConnectedState); + + // send initial presence + sendPacket(d->clientPresence); +} + +void QXmppClient::_q_streamDisconnected() +{ + // notify managers + emit disconnected(); + emit stateChanged(QXmppClient::DisconnectedState); +} + +/// Returns the QXmppLogger associated with the current QXmppClient. + +QXmppLogger *QXmppClient::logger() const +{ + return d->logger; +} + +/// Sets the QXmppLogger associated with the current QXmppClient. + +void QXmppClient::setLogger(QXmppLogger *logger) +{ + if (logger != d->logger) { + if (d->logger) { + disconnect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), + d->logger, SLOT(log(QXmppLogger::MessageType,QString))); + } + + d->logger = logger; + if (d->logger) { + connect(this, SIGNAL(logMessage(QXmppLogger::MessageType,QString)), + d->logger, SLOT(log(QXmppLogger::MessageType,QString))); + } + + emit loggerChanged(d->logger); + } +} + |
