aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2010-08-23 05:49:24 +0000
committerJeremy Lainé <jeremy.laine@m4x.org>2010-08-23 05:49:24 +0000
commit6c462ee694b614f538cfbee894134f723ae58820 (patch)
tree53e3398d261222ad0c8209fac35057dc3dd86050 /src
parent12418dc2d452f372c19d129a1dacfbf4e7e00817 (diff)
downloadqxmpp-6c462ee694b614f538cfbee894134f723ae58820.tar.gz
- add support for incoming C2S connections
- add support for incoming S2S connections - add support for outgoing S2S connections
Diffstat (limited to 'src')
-rw-r--r--src/QXmppIncomingClient.cpp281
-rw-r--r--src/QXmppIncomingClient.h71
-rw-r--r--src/QXmppIncomingServer.cpp177
-rw-r--r--src/QXmppIncomingServer.h62
-rw-r--r--src/QXmppOutgoingServer.cpp177
-rw-r--r--src/QXmppOutgoingServer.h63
-rw-r--r--src/src.pro6
7 files changed, 837 insertions, 0 deletions
diff --git a/src/QXmppIncomingClient.cpp b/src/QXmppIncomingClient.cpp
new file mode 100644
index 00000000..0e51958c
--- /dev/null
+++ b/src/QXmppIncomingClient.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2008-2010 The QXmpp developers
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * 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 <QDomElement>
+#include <QSslKey>
+#include <QSslSocket>
+#include <QTimer>
+
+#include "QXmppBind.h"
+#include "QXmppConstants.h"
+#include "QXmppMessage.h"
+#include "QXmppSession.h"
+#include "QXmppStreamFeatures.h"
+#include "QXmppUtils.h"
+
+#include "QXmppIncomingClient.h"
+
+class QXmppIncomingClientPrivate
+{
+public:
+ QTimer *idleTimer;
+
+ QString domain;
+ QString username;
+ QString resource;
+ QXmppPasswordChecker *passwordChecker;
+ QByteArray saslNonce;
+};
+
+QXmppIncomingClient::QXmppIncomingClient(QSslSocket *socket, const QString &domain, QObject *parent)
+ : QXmppStream(parent),
+ d(new QXmppIncomingClientPrivate)
+{
+ d->passwordChecker = 0;
+ d->domain = domain;
+
+ setObjectName("C2S");
+ setSocket(socket);
+
+ // create inactivity timer
+ d->idleTimer = new QTimer(this);
+ d->idleTimer->setInterval(70000);
+ d->idleTimer->setSingleShot(true);
+ bool check = connect(d->idleTimer, SIGNAL(timeout()),
+ this, SLOT(slotTimeout()));
+ Q_ASSERT(check);
+}
+
+QXmppIncomingClient::~QXmppIncomingClient()
+{
+ delete d;
+}
+
+bool QXmppIncomingClient::isConnected() const
+{
+ return !d->username.isEmpty();
+}
+
+QString QXmppIncomingClient::jid() const
+{
+ if (d->username.isEmpty())
+ return QString();
+ QString jid = d->username + "@" + d->domain;
+ if (!d->resource.isEmpty())
+ jid += "/" + d->resource;
+ return jid;
+}
+
+void QXmppIncomingClient::setPasswordChecker(QXmppPasswordChecker *checker)
+{
+ d->passwordChecker = checker;
+}
+
+void QXmppIncomingClient::handleStream(const QDomElement &streamElement)
+{
+ Q_UNUSED(streamElement);
+
+ d->idleTimer->start();
+
+ // start stream
+ const QByteArray sessionId = generateStanzaHash().toAscii();
+ QString response = QString("<?xml version='1.0'?><stream:stream"
+ " xmlns=\"%1\" xmlns:stream=\"%2\""
+ " id=\"%3\" from=\"%4\" version=\"1.0\" xml:lang=\"en\">").arg(
+ ns_client,
+ ns_stream,
+ sessionId,
+ d->domain.toAscii());
+ sendData(response.toUtf8());
+
+ // send stream features
+ QXmppStreamFeatures features;
+ if (!socket()->isEncrypted() && !socket()->localCertificate().isNull() && !socket()->privateKey().isNull())
+ features.setSecurityMode(QXmppConfiguration::TLSEnabled);
+ if (!d->username.isEmpty())
+ {
+ features.setBindAvailable(true);
+ features.setSessionAvailable(true);
+ }
+ else
+ {
+ QList<QXmppConfiguration::SASLAuthMechanism> mechanisms;
+ mechanisms << QXmppConfiguration::SASLPlain;
+ mechanisms << QXmppConfiguration::SASLDigestMD5;
+ features.setAuthMechanisms(mechanisms);
+ }
+ sendPacket(features);
+}
+
+void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv)
+{
+ const QString ns = nodeRecv.namespaceURI();
+
+ d->idleTimer->start();
+
+ if (ns == ns_tls && nodeRecv.tagName() == "starttls")
+ {
+ sendData("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+ socket()->flush();
+ socket()->startServerEncryption();
+ return;
+ }
+ else if (ns == ns_sasl)
+ {
+ if (nodeRecv.tagName() == "auth")
+ {
+ const QString mechanism = nodeRecv.attribute("mechanism");
+ if (mechanism == "PLAIN")
+ {
+ QList<QByteArray> auth = QByteArray::fromBase64(nodeRecv.text().toAscii()).split('\0');
+ if (auth.size() != 3)
+ {
+ sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
+ disconnectFromHost();
+ return;
+ }
+
+ const QString username = QString::fromUtf8(auth[1]);
+ const QString password = QString::fromUtf8(auth[2]);
+ if (d->passwordChecker && d->passwordChecker->check(username, password))
+ {
+ d->username = username;
+ sendData("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
+ } else {
+ sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>");
+ disconnectFromHost();
+ return;
+ }
+ }
+ else if (mechanism == "DIGEST-MD5")
+ {
+ // generate nonce
+ QByteArray nonce(32, 'm');
+ for(int n = 0; n < nonce.size(); ++n)
+ nonce[n] = (char)(256.0*qrand()/(RAND_MAX+1.0));
+ d->saslNonce = nonce.toBase64();
+
+ QMap<QByteArray, QByteArray> challenge;
+ challenge["nonce"] = d->saslNonce;
+ challenge["realm"] = d->domain.toUtf8();
+ challenge["qop"] = "auth";
+ challenge["charset"] = "utf-8";
+ challenge["algorithm"] = "md5-sess";
+
+ const QByteArray data = serializeDigestMd5(challenge).toBase64();
+ sendData("<challenge xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>" + data +"</challenge>");
+ }
+ else
+ {
+ // unsupported method
+ sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'></failure>");
+ disconnectFromHost();
+ return;
+ }
+ }
+ else if (nodeRecv.tagName() == "response")
+ {
+ const QByteArray raw = QByteArray::fromBase64(nodeRecv.text().toAscii());
+ QMap<QByteArray, QByteArray> response = parseDigestMd5(raw);
+
+ // check credentials
+ const QString username = QString::fromUtf8(response.value("username"));
+ QString password;
+ if (!d->passwordChecker || !d->passwordChecker->get(username, password))
+ {
+ sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>");
+ disconnectFromHost();
+ return;
+ }
+ const QByteArray a1 = username.toUtf8() + ':' + d->domain.toUtf8() + ':' + password.toUtf8();
+ const QByteArray remote = QByteArray::fromHex(response["response"]);
+ if (remote != calculateDigestMd5(a1,
+ d->saslNonce,
+ response.value("nc"),
+ response.value("cnonce"),
+ response.value("digest-uri"),
+ QByteArray()))
+ {
+ sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'><not-authorized/></failure>");
+ disconnectFromHost();
+ return;
+ }
+
+ // authentication succeeded
+ d->username = username;
+ sendData("<success xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
+ }
+ }
+ else if (ns == ns_client)
+ {
+ if (nodeRecv.tagName() == "iq")
+ {
+ const QString type = nodeRecv.attribute("type");
+ if (QXmppBind::isBind(nodeRecv) && type == "set")
+ {
+ QXmppBind bindSet;
+ bindSet.parse(nodeRecv);
+ d->resource = bindSet.resource();
+
+ QXmppBind bindResult(QXmppIq::Result);
+ bindResult.setId(bindSet.id());
+ bindResult.setJid(jid());
+ sendPacket(bindResult);
+
+ // bound
+ emit connected();
+ }
+ else if (QXmppSession::isSession(nodeRecv) && type == "set")
+ {
+ QXmppSession sessionSet;
+ sessionSet.parse(nodeRecv);
+
+ QXmppSession sessionResult(QXmppIq::Result);
+ sessionResult.setId(sessionSet.id());
+ sendPacket(sessionResult);
+ }
+ else
+ {
+ QDomElement nodeFull(nodeRecv);
+ nodeFull.setAttribute("from", jid());
+ bool handled = false;
+ emit elementReceived(nodeFull, handled);
+ }
+ }
+ else if (nodeRecv.tagName() == "message" || nodeRecv.tagName() == "presence")
+ {
+ QDomElement nodeFull(nodeRecv);
+ nodeFull.setAttribute("from", jid());
+ bool handled = false;
+ emit elementReceived(nodeFull, handled);
+ }
+ }
+}
+
+void QXmppIncomingClient::slotTimeout()
+{
+ warning(QString("Idle timeout for %1").arg(jid()));
+ disconnectFromHost();
+}
+
+
diff --git a/src/QXmppIncomingClient.h b/src/QXmppIncomingClient.h
new file mode 100644
index 00000000..a09fcf5f
--- /dev/null
+++ b/src/QXmppIncomingClient.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2008-2010 The QXmpp developers
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * 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.
+ *
+ */
+
+#ifndef QXMPPINCOMINGCLIENT_H
+#define QXMPPINCOMINGCLIENT_H
+
+#include "QXmppStream.h"
+
+class QXmppIncomingClientPrivate;
+
+/// Interface for password checkers.
+///
+/// FIXME : make this an abstract class
+
+class QXmppPasswordChecker
+{
+public:
+ virtual bool check(const QString &username, const QString &password) = 0;
+ virtual bool get(const QString &username, QString &password) = 0;
+};
+
+/// The QXmppIncomingClient class represents an incoming XMPP stream
+/// from an XMPP client.
+///
+
+class QXmppIncomingClient : public QXmppStream
+{
+ Q_OBJECT
+
+public:
+ QXmppIncomingClient(QSslSocket *socket, const QString &domain, QObject *parent = 0);
+ ~QXmppIncomingClient();
+
+ bool isConnected() const;
+ QString jid() const;
+
+ void setPasswordChecker(QXmppPasswordChecker *checker);
+
+protected:
+ void handleStream(const QDomElement &element);
+ void handleStanza(const QDomElement &element);
+
+private slots:
+ void slotTimeout();
+
+private:
+ Q_DISABLE_COPY(QXmppIncomingClient)
+ QXmppIncomingClientPrivate* const d;
+};
+
+#endif
diff --git a/src/QXmppIncomingServer.cpp b/src/QXmppIncomingServer.cpp
new file mode 100644
index 00000000..24775360
--- /dev/null
+++ b/src/QXmppIncomingServer.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2008-2010 The QXmpp developers
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * 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 <QDomElement>
+#include <QSslKey>
+#include <QSslSocket>
+
+#include "QXmppConstants.h"
+#include "QXmppDialback.h"
+#include "QXmppIncomingServer.h"
+#include "QXmppOutgoingServer.h"
+#include "QXmppStreamFeatures.h"
+#include "QXmppUtils.h"
+
+class QXmppIncomingServerPrivate
+{
+public:
+ bool authenticated;
+ QString domain;
+ QString localStreamId;
+};
+
+QXmppIncomingServer::QXmppIncomingServer(QSslSocket *socket, const QString &domain, QObject *parent)
+ : QXmppStream(parent),
+ d(new QXmppIncomingServerPrivate)
+{
+ setObjectName("S2S-in");
+ setSocket(socket);
+ d->authenticated = false;
+ d->domain = domain;
+}
+
+QXmppIncomingServer::~QXmppIncomingServer()
+{
+ delete d;
+}
+
+void QXmppIncomingServer::handleStream(const QDomElement &streamElement)
+{
+ if (!streamElement.attribute("from").isEmpty())
+ setObjectName("S2S-in-" + streamElement.attribute("from"));
+
+ // start stream
+ d->localStreamId = generateStanzaHash().toAscii();
+ QString data = QString("<?xml version='1.0'?><stream:stream"
+ " xmlns='%1' xmlns:db='%2' xmlns:stream='%3'"
+ " id='%4' version=\"1.0\">").arg(
+ ns_server,
+ ns_server_dialback,
+ ns_stream,
+ d->localStreamId);
+ sendData(data.toUtf8());
+
+ // send stream features
+ QXmppStreamFeatures features;
+ if (!socket()->isEncrypted() && !socket()->localCertificate().isNull() && !socket()->privateKey().isNull())
+ features.setSecurityMode(QXmppConfiguration::TLSEnabled);
+ sendPacket(features);
+}
+
+void QXmppIncomingServer::handleStanza(const QDomElement &stanza)
+{
+ const QString ns = stanza.namespaceURI();
+
+ if (ns == ns_tls && stanza.tagName() == "starttls")
+ {
+ sendData("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
+ socket()->flush();
+ socket()->startServerEncryption();
+ return;
+ }
+ else if (QXmppDialback::isDialback(stanza))
+ {
+ QXmppDialback request;
+ request.parse(stanza);
+ // check the request is valid
+ if (!request.type().isEmpty() ||
+ request.from().isEmpty() ||
+ request.to() != d->domain ||
+ request.key().isEmpty())
+ {
+ warning("Invalid dialback received");
+ return;
+ }
+
+ const QString domain = request.from();
+ setObjectName("S2S-in-" + domain);
+
+ if (request.command() == QXmppDialback::Result)
+ {
+ // etablish dialback connection
+ QXmppOutgoingServer *stream = new QXmppOutgoingServer(d->domain, this);
+ stream->setLogger(logger());
+ stream->setObjectName("S2S-dialback-" + domain);
+ stream->configuration().setDomain(domain);
+ stream->configuration().setHost(domain);
+ stream->configuration().setPort(5269);
+ bool check = connect(stream, SIGNAL(dialbackResponseReceived(QXmppDialback)),
+ this, SLOT(slotDialbackResponseReceived(QXmppDialback)));
+ Q_ASSERT(check);
+ stream->setVerify(d->localStreamId, request.key());
+ stream->connectToHost();
+ } else {
+ emit dialbackRequestReceived(request);
+ }
+
+ } else if (d->authenticated) {
+ // relay packets if the remote party is authenticated
+ bool handled = false;
+ emit elementReceived(stanza, handled);
+ } else {
+ warning("Received an element, but remote party is not authenticated");
+ }
+}
+
+QString QXmppIncomingServer::localStreamId() const
+{
+ return d->localStreamId;
+}
+
+/// Handles a dialback response received from the authority server.
+///
+/// \param response
+///
+
+void QXmppIncomingServer::slotDialbackResponseReceived(const QXmppDialback &dialback)
+{
+ QXmppOutgoingServer *stream = qobject_cast<QXmppOutgoingServer*>(sender());
+ if (!stream ||
+ dialback.command() != QXmppDialback::Verify ||
+ dialback.id() != d->localStreamId)
+ return;
+
+ // relay verify response
+ QXmppDialback response;
+ response.setCommand(QXmppDialback::Result);
+ response.setTo(dialback.from());
+ response.setFrom(d->domain);
+ response.setType(dialback.type());
+ sendPacket(response);
+
+ // check for success
+ if (response.type() == "valid")
+ {
+ info("Incoming stream is ready");
+ d->authenticated = true;
+ emit connected();
+ } else {
+ disconnectFromHost();
+ }
+
+ // disconnect dialback
+ stream->disconnectFromHost();
+ stream->deleteLater();
+}
+
+
diff --git a/src/QXmppIncomingServer.h b/src/QXmppIncomingServer.h
new file mode 100644
index 00000000..52372813
--- /dev/null
+++ b/src/QXmppIncomingServer.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2008-2010 The QXmpp developers
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * 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.
+ *
+ */
+
+#ifndef QXMPPINCOMINGSERVER_H
+#define QXMPPINCOMINGSERVER_H
+
+#include "QXmppStream.h"
+
+class QXmppDialback;
+class QXmppIncomingServerPrivate;
+class QXmppOutgoingServer;
+
+/// The QXmppIncomingServer class represents an incoming XMPP stream
+/// from an XMPP server.
+///
+
+class QXmppIncomingServer : public QXmppStream
+{
+ Q_OBJECT
+
+public:
+ QXmppIncomingServer(QSslSocket *socket, const QString &domain, QObject *parent);
+ ~QXmppIncomingServer();
+
+ QString localStreamId() const;
+
+signals:
+ void dialbackRequestReceived(const QXmppDialback &result);
+
+protected:
+ void handleStanza(const QDomElement &stanzaElement);
+ void handleStream(const QDomElement &streamElement);
+
+private slots:
+ void slotDialbackResponseReceived(const QXmppDialback &dialback);
+
+private:
+ Q_DISABLE_COPY(QXmppIncomingServer)
+ QXmppIncomingServerPrivate* const d;
+};
+
+#endif
diff --git a/src/QXmppOutgoingServer.cpp b/src/QXmppOutgoingServer.cpp
new file mode 100644
index 00000000..d5daa316
--- /dev/null
+++ b/src/QXmppOutgoingServer.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2008-2010 The QXmpp developers
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * 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 <QDomElement>
+#include <QSslKey>
+#include <QSslSocket>
+
+#include "QXmppConstants.h"
+#include "QXmppDialback.h"
+#include "QXmppOutgoingServer.h"
+#include "QXmppStreamFeatures.h"
+#include "QXmppUtils.h"
+
+class QXmppOutgoingServerPrivate
+{
+public:
+ QString domain;
+ QString incomingId;
+ QString incomingKey;
+ QString localStreamKey;
+ bool ready;
+};
+
+/// Constructs a new outgoing server-to-server stream.
+///
+/// \param socket
+/// \param domain the local domain
+/// \param parent the parent object
+///
+
+QXmppOutgoingServer::QXmppOutgoingServer(const QString &domain, QObject *parent)
+ : QXmppOutgoingClient(parent),
+ d(new QXmppOutgoingServerPrivate)
+{
+ d->domain = domain;
+ d->ready = false;
+ configuration().setKeepAliveInterval(0);
+}
+
+/// Destroys the stream.
+///
+
+QXmppOutgoingServer::~QXmppOutgoingServer()
+{
+ delete d;
+}
+
+void QXmppOutgoingServer::handleStart()
+{
+ QString data = QString("<?xml version='1.0'?><stream:stream"
+ " xmlns='%1' xmlns:db='%2' xmlns:stream='%3' version='1.0'>").arg(
+ ns_server,
+ ns_server_dialback,
+ ns_stream);
+ sendData(data.toUtf8());
+}
+
+void QXmppOutgoingServer::handleStanza(const QDomElement &stanza)
+{
+ const QString ns = stanza.namespaceURI();
+
+ if(QXmppStreamFeatures::isStreamFeatures(stanza))
+ {
+ QXmppStreamFeatures features;
+ features.parse(stanza);
+ if (features.securityMode() != QXmppConfiguration::TLSDisabled)
+ {
+ // let QXmppOutgoingClient handle TLS
+ QXmppOutgoingClient::handleStanza(stanza);
+ }
+ else if (!d->localStreamKey.isEmpty())
+ {
+ // send dialback key
+ QXmppDialback dialback;
+ dialback.setCommand(QXmppDialback::Result);
+ dialback.setFrom(d->domain);
+ dialback.setTo(configuration().domain());
+ dialback.setKey(d->localStreamKey);
+ sendPacket(dialback);
+ }
+ else if (!d->incomingId.isEmpty() && !d->incomingKey.isEmpty())
+ {
+ // send dialback verify
+ QXmppDialback verify;
+ verify.setCommand(QXmppDialback::Verify);
+ verify.setId(d->incomingId);
+ verify.setTo(configuration().domain());
+ verify.setFrom(d->domain);
+ verify.setKey(d->incomingKey);
+ sendPacket(verify);
+ }
+ }
+ else if (ns == ns_tls)
+ {
+ if (stanza.tagName() == "proceed")
+ {
+ debug("Starting encryption");
+ socket()->startClientEncryption();
+ return;
+ }
+ }
+ else if (QXmppDialback::isDialback(stanza))
+ {
+ QXmppDialback response;
+ response.parse(stanza);
+
+ // check the request is valid
+ if (response.from().isEmpty() ||
+ response.to() != d->domain ||
+ response.type().isEmpty())
+ {
+ warning("Invalid dialback response received");
+ return;
+ }
+ if (response.command() == QXmppDialback::Result)
+ {
+ if (response.type() == "valid")
+ {
+ info("Outgoing stream is ready");
+ d->ready = true;
+ emit connected();
+ }
+ }
+ else if (response.command() == QXmppDialback::Verify)
+ {
+ emit dialbackResponseReceived(response);
+ }
+
+ }
+ else
+ {
+ bool handled = false;
+ emit elementReceived(stanza, handled);
+ }
+}
+
+bool QXmppOutgoingServer::isConnected() const
+{
+ return d->ready;
+}
+
+QString QXmppOutgoingServer::localStreamKey() const
+{
+ return d->localStreamKey;
+}
+
+void QXmppOutgoingServer::setLocalStreamKey(const QString &key)
+{
+ d->localStreamKey = key;
+}
+
+void QXmppOutgoingServer::setVerify(const QString &id, const QString &key)
+{
+ d->incomingId = id;
+ d->incomingKey = key;
+}
+
diff --git a/src/QXmppOutgoingServer.h b/src/QXmppOutgoingServer.h
new file mode 100644
index 00000000..5d3e67d4
--- /dev/null
+++ b/src/QXmppOutgoingServer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008-2010 The QXmpp developers
+ *
+ * Author:
+ * Jeremy Lainé
+ *
+ * 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.
+ *
+ */
+
+#ifndef QXMPPOUTGOINGSERVER_H
+#define QXMPPOUTGOINGSERVER_H
+
+#include "QXmppOutgoingClient.h"
+
+class QXmppDialback;
+class QXmppOutgoingServer;
+class QXmppOutgoingServerPrivate;
+
+/// The QXmppOutgoingServer class represents an outgoing XMPP stream
+/// to another XMPP server.
+///
+
+class QXmppOutgoingServer : public QXmppOutgoingClient
+{
+ Q_OBJECT
+
+public:
+ QXmppOutgoingServer(const QString &domain, QObject *parent);
+ ~QXmppOutgoingServer();
+
+ bool isConnected() const;
+
+ QString localStreamKey() const;
+ void setLocalStreamKey(const QString &key);
+ void setVerify(const QString &id, const QString &key);
+
+signals:
+ void dialbackResponseReceived(const QXmppDialback &response);
+
+protected:
+ void handleStart();
+ void handleStanza(const QDomElement &stanzaElement);
+
+private:
+ Q_DISABLE_COPY(QXmppOutgoingServer)
+ QXmppOutgoingServerPrivate* const d;
+};
+
+#endif
diff --git a/src/src.pro b/src/src.pro
index 74e71c78..14d20884 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -33,6 +33,8 @@ HEADERS += QXmppUtils.h \
QXmppDiscoveryIq.h \
QXmppElement.h \
QXmppIbbIq.h \
+ QXmppIncomingClient.h \
+ QXmppIncomingServer.h \
QXmppInvokable.h \
QXmppIq.h \
QXmppJingleIq.h \
@@ -42,6 +44,7 @@ HEADERS += QXmppUtils.h \
QXmppMucManager.h \
QXmppNonSASLAuth.h \
QXmppOutgoingClient.h \
+ QXmppOutgoingServer.h \
QXmppPacket.h \
QXmppPingIq.h \
QXmppPresence.h \
@@ -79,6 +82,8 @@ SOURCES += QXmppUtils.cpp \
QXmppDiscoveryIq.cpp \
QXmppElement.cpp \
QXmppIbbIq.cpp \
+ QXmppIncomingClient.cpp \
+ QXmppIncomingServer.cpp \
QXmppInvokable.cpp \
QXmppIq.cpp \
QXmppJingleIq.cpp \
@@ -88,6 +93,7 @@ SOURCES += QXmppUtils.cpp \
QXmppMucManager.cpp \
QXmppNonSASLAuth.cpp \
QXmppOutgoingClient.cpp \
+ QXmppOutgoingServer.cpp \
QXmppPacket.cpp \
QXmppPingIq.cpp \
QXmppPresence.cpp \