bool QXmppBookmarkManager::handleStanza(const QDomElement &stanza)
{
    if (stanza.tagName() == "iq")
    {
        if (QXmppPrivateStorageIq::isPrivateStorageIq(stanza))
        {
            QXmppPrivateStorageIq iq;
            iq.parse(stanza);

            if (iq.type() == QXmppIq::Result)
            {
                d->bookmarks = iq.bookmarks();
                d->bookmarksReceived = true;
                emit bookmarksReceived(d->bookmarks);
            }
            return true;
        }
        else if (!d->pendingId.isEmpty() && stanza.attribute("id") == d->pendingId)
        {
            QXmppIq iq;
            iq.parse(stanza);
            if (iq.type() == QXmppIq::Result)
            {
                d->bookmarks = d->pendingBookmarks;
                emit bookmarksReceived(d->bookmarks);
            }
            d->pendingId = QString();
            return true;
        }
    }
    return false;
}
	bool LastActivityManager::handleStanza (const QDomElement& elem)
	{
		if (elem.tagName () != "iq")
			return false;
		
		const QDomElement& query = elem.firstChildElement ("query");
		if (query.namespaceURI () != NsLastActivity)
			return false;
		
		const QString& from = elem.attribute ("from");
		
		if (elem.attribute ("type") == "get")
		{
			IPluginsManager *pMgr = Core::Instance ()
					.GetProxy ()->GetPluginsManager ();
			ILastActivityProvider *prov = pMgr->
					GetAllCastableTo<ILastActivityProvider*> ().value (0);
					
			if (!prov)
				return false;

			QXmppIq iq = CreateIq (from, prov->GetInactiveSeconds ());
			iq.setType (QXmppIq::Result);
			iq.setId (elem.attribute ("id"));
			
			client ()->sendPacket (iq);
		}
		else if (elem.attribute ("type") == "result" &&
				query.hasAttribute ("seconds"))
			emit gotLastActivity (from, query.attribute ("seconds").toInt ());
		
		return true;
	}
int QXmppCallWebrtcManager::SendAck(QXmppWebRtcIq iq)
{
    QXmppIq ack;
    ack.setId(iq.id());
    ack.setTo(iq.from());
    ack.setType(QXmppIq::Result);
    return client()->sendPacket(ack);
}
	bool JabberSearchManager::CheckError (const QDomElement& elem)
	{
		if (elem.firstChildElement ("error").isNull ())
			return false;

		QXmppIq iq;
		iq.parse (elem);

		emit gotServerError (iq);

		return true;
	}
Example #5
0
void tst_QXmppIq::testBasic()
{
    QFETCH(QByteArray, xml);
    QFETCH(int, type);

    QXmppIq iq;
    parsePacket(iq, xml);
    QCOMPARE(iq.to(), QString("[email protected]/QXmpp"));
    QCOMPARE(iq.from(), QString("[email protected]/QXmpp"));
    QCOMPARE(int(iq.type()), type);
    serializePacket(iq, xml);
}
	QXmppIq LastActivityManager::CreateIq (const QString& to, int secs)
	{
		QXmppIq iq;
		iq.setTo (to);

		QXmppElement queryElem;
		queryElem.setAttribute ("xmlns", NsLastActivity);
		if (secs != -1)
			queryElem.setAttribute ("seconds", QString::number (secs));
		iq.setExtensions (queryElem);
		
		return iq;
	}
	void ClientConnectionErrorMgr::HandleIq (const QXmppIq& iq)
	{
		switch (iq.error ().type ())
		{
		case QXmppStanza::Error::Cancel:
		case QXmppStanza::Error::Continue:
		case QXmppStanza::Error::Modify:
		case QXmppStanza::Error::Auth:
		case QXmppStanza::Error::Wait:
			HandleError (iq);
			break;
		default:
			WhitelistedErrors_.remove (iq.id ());
			break;
		}
	}
	void AdHocCommandServer::SendCompleted (const QDomElement& sourceElem,
			const QString& node, const QString& sessionId)
	{
		QXmppElement elem;
		elem.setTagName ("command");
		elem.setAttribute ("xmlns", NsCommands);
		elem.setAttribute ("node", node);
		elem.setAttribute ("status", "completed");
		elem.setAttribute ("sessionid", sessionId);

		QXmppIq iq;
		iq.setTo (sourceElem.attribute ("from"));
		iq.setId (sourceElem.attribute ("id"));
		iq.setType (QXmppIq::Result);
		iq.setExtensions (QXmppElementList () << elem);

		Conn_->GetClient ()->sendPacket (iq);
	}
	void ClientConnectionErrorMgr::HandleError (const QXmppIq& iq)
	{
		const QXmppStanza::Error& error = iq.error ();
		if (!WhitelistedErrors_.remove (iq.id ()))
			switch (error.condition ())
			{
			case QXmppStanza::Error::FeatureNotImplemented:
			case QXmppStanza::Error::ItemNotFound:
			case QXmppStanza::Error::ServiceUnavailable:
				return;
			default:
				break;
			}

		QString typeText;
		if (!iq.from ().isEmpty ())
			typeText = tr ("Error from %1: ")
					.arg (iq.from ());
		typeText += HandleErrorCondition (error.condition ());

		if (!error.text ().isEmpty ())
			typeText += " " + tr ("Error text: %1.")
					.arg (error.text ());

		const Entity& e = Util::MakeNotification ("Azoth",
				typeText,
				PCritical_);
		Core::Instance ().SendEntity (e);

		const bool dontTryFurther = error.type () == QXmppStanza::Error::Cancel ||
			(error.type () == QXmppStanza::Error::Auth &&
			 error.condition () != QXmppStanza::Error::NotAuthorized);
		if (dontTryFurther && !ClientConn_->GetClient ()->isConnected ())
		{
			GlooxAccountState state =
			{
				SOffline,
				QString (),
				0
			};
			ClientConn_->SetState (state);
		}
	}
	bool LegacyEntityTimeExt::handleStanza (const QDomElement& elem)
	{
		if (elem.tagName () != "iq" ||
				elem.attribute ("type") != "get")
			return false;

		if (elem.firstChildElement ("query").namespaceURI () != NsLegacyEntityTime)
			return false;

		const QString& from = elem.attribute ("from");
		if (from.isEmpty ())
			return false;

		const QDateTime& date = QDateTime::currentDateTime ().toUTC ();

		QXmppElement utcElem;
		utcElem.setTagName ("utc");
		utcElem.setValue (date.toString ("yyyyMMddThh:mm:ss"));

		const QString& displayStr = "Your client/bot sucks since it "
				"uses the long-deprecated XEP-0090. Upgrade your code. "
				"Ah, and, regarding your question, it's " +
				QDateTime::currentDateTime ().toString () + " here";
		QXmppElement displayElem;
		displayElem.setTagName ("display");
		displayElem.setValue (displayStr);

		QXmppElement queryElem;
		queryElem.setTagName ("query");
		queryElem.setAttribute ("xmlns", NsLegacyEntityTime);
		queryElem.appendChild (utcElem);
		queryElem.appendChild (displayElem);

		QXmppIq iq (QXmppIq::Result);
		iq.setTo (from);
		iq.setId (elem.attribute ("id"));
		iq.setExtensions (QXmppElementList () << queryElem);

		client ()->sendPacket (iq);

		return true;
	}
Example #11
0
	void GlooxAccount::UpdateServerPassword (const QString& newPass)
	{
		if (newPass.isEmpty ())
			return;

		const QString nsRegister = "jabber:iq:register";

		const auto& jid = SettingsHolder_->GetJID ();
		const auto aPos = jid.indexOf ('@');

		QXmppElement userElem;
		userElem.setTagName ("username");
		userElem.setValue (aPos > 0 ? jid.left (aPos) : jid);

		QXmppElement passElem;
		passElem.setTagName ("password");
		passElem.setValue (newPass);

		QXmppElement queryElem;
		queryElem.setTagName ("query");
		queryElem.setAttribute ("xmlns", nsRegister);
		queryElem.appendChild (userElem);
		queryElem.appendChild (passElem);

		QXmppIq iq (QXmppIq::Set);
		iq.setTo (GetDefaultReqHost ());
		iq.setExtensions ({ queryElem });

		ClientConnection_->SendPacketWCallback (iq,
				[this, newPass] (const QXmppIq& reply) -> void
				{
					if (reply.type () != QXmppIq::Result)
						return;

					emit serverPasswordUpdated (newPass);
					Core::Instance ().GetPluginProxy ()->SetPassword (newPass, this);
					ClientConnection_->SetPassword (newPass);
				});
	}
Example #12
0
bool XmppServerProxy65::handleStanza(const QDomElement &element)
{
    if (element.attribute("to") != d->jid)
        return false;

    if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element))
    {
        QXmppDiscoveryIq discoIq;
        discoIq.parse(element);

        if (discoIq.type() == QXmppIq::Get)
        {
            QXmppDiscoveryIq responseIq;
            responseIq.setTo(discoIq.from());
            responseIq.setFrom(discoIq.to());
            responseIq.setId(discoIq.id());
            responseIq.setType(QXmppIq::Result);
            responseIq.setQueryType(discoIq.queryType());

            if (discoIq.queryType() == QXmppDiscoveryIq::InfoQuery)
            {
                QStringList features = QStringList() << ns_disco_info << ns_disco_items << ns_bytestreams;

                QList<QXmppDiscoveryIq::Identity> identities;
                QXmppDiscoveryIq::Identity identity;
                identity.setCategory("proxy");
                identity.setType("bytestreams");
                identity.setName("SOCKS5 Bytestreams");
                identities.append(identity);

                responseIq.setFeatures(features);
                responseIq.setIdentities(identities);
            }

            server()->sendPacket(responseIq);
            return true;
        }
    }
    else if (element.tagName() == "iq" && QXmppByteStreamIq::isByteStreamIq(element))
    {
        QXmppByteStreamIq bsIq;
        bsIq.parse(element);

        if (bsIq.type() == QXmppIq::Get)
        {
            // request for the proxy's network address
            if (d->allowedDomains.contains(QXmppUtils::jidToDomain(bsIq.from()))) {
                QXmppByteStreamIq responseIq;
                responseIq.setType(QXmppIq::Result);
                responseIq.setTo(bsIq.from());
                responseIq.setFrom(bsIq.to());
                responseIq.setId(bsIq.id());

                QList<QXmppByteStreamIq::StreamHost> streamHosts;

                QXmppByteStreamIq::StreamHost streamHost;
                streamHost.setJid(d->jid);
                streamHost.setHost(d->hostAddress.toString());
                streamHost.setPort(d->port);
                streamHosts.append(streamHost);

                responseIq.setStreamHosts(streamHosts);
                server()->sendPacket(responseIq);
            } else {
                QXmppIq responseIq;
                responseIq.setType(QXmppIq::Error);
                responseIq.setTo(bsIq.from());
                responseIq.setFrom(bsIq.to());
                responseIq.setId(bsIq.id());
                responseIq.setError(QXmppStanza::Error(QXmppStanza::Error::Auth, QXmppStanza::Error::Forbidden));
                server()->sendPacket(responseIq);
            }
        }
        else if (bsIq.type() == QXmppIq::Set)
        {
            QString hash = streamHash(bsIq.sid(), bsIq.from(), bsIq.activate());
            QTcpSocketPair *pair = d->pairs.value(hash);

            QXmppIq responseIq;
            responseIq.setTo(bsIq.from());
            responseIq.setFrom(bsIq.to());
            responseIq.setId(bsIq.id());

            if (pair &&
                d->allowedDomains.contains(QXmppUtils::jidToDomain(bsIq.from())))
            {
                if (pair->activate()) {
                    info(QString("Activated connection %1 by %2").arg(hash, bsIq.from()));
                    responseIq.setType(QXmppIq::Result);
                } else {
                    warning(QString("Failed to activate connection %1 by %2").arg(hash, bsIq.from()));
                    responseIq.setType(QXmppIq::Error);
                }
            } else {
                warning(QString("Not activating connection %1 by %2").arg(hash, bsIq.from()));
                responseIq.setType(QXmppIq::Error);
            }
            server()->sendPacket(responseIq);
        }
        return true;
    }
    return false;
}
Example #13
0
bool XmppServerPrivate::handleStanza(const QDomElement &element)
{
    const QString to = element.attribute("to");
    if (QXmppUtils::jidToDomain(to) != server()->domain())
        return false;

    if (element.tagName() == "iq" && PrivateStorageIq::isPrivateStorageIq(element))
    {
        PrivateStorageIq request;
        request.parse(element);

        if (request.type() == QXmppIq::Result)
            return true;

        // check the namespace is valid
        const QString xmlns = request.payload().attribute("xmlns");
        if (xmlns.isEmpty()) {
            QXmppIq response;
            response.setId(request.id());
            response.setTo(request.from());
            response.setType(QXmppIq::Error);
            server()->sendPacket(response);
            return true;
        }

        const QString bareFrom = QXmppUtils::jidToBareJid(request.from());
        QDjangoQuerySet<PrivateStorage> qs;
        qs = qs.filter(QDjangoWhere("jid", QDjangoWhere::Equals, bareFrom));

        if (request.type() == QXmppIq::Get) {
            PrivateStorageIq response;
            response.setId(request.id());
            response.setTo(request.from());
            response.setType(QXmppIq::Result);
 
            PrivateStorage storage;
            if (qs.get(QDjangoWhere("xmlns", QDjangoWhere::Equals, xmlns), &storage)) {
                QDomDocument doc;
                doc.setContent(storage.data());
                response.setPayload(doc.documentElement());
            } else {
                response.setPayload(request.payload());
            }
            server()->sendPacket(response);

        } else if (request.type() == QXmppIq::Set) {
            PrivateStorage storage;
            if (!qs.get(QDjangoWhere("xmlns", QDjangoWhere::Equals, xmlns), &storage)) {
                storage.setJid(bareFrom);
                storage.setXmlns(xmlns);
            }
            storage.setXml(request.payload());
            storage.save();

            // reply
            QXmppIq response;
            response.setId(request.id());
            response.setTo(request.from());
            response.setType(QXmppIq::Result);
            server()->sendPacket(response);
        }
        return true;
    }
    return false;
}
Example #14
0
bool JabberErrorService::isErrorIq(const QXmppIq &iq) const
{
	return iq.type() == QXmppIq::Type::Error;
}
void QXmppIncomingClient::handleStanza (const QDomElement &nodeRecv)
{
    const QString ns = nodeRecv.namespaceURI();

    if (d->idleTimer->interval())
        d->idleTimer->start();

    if (ns == ns_tls && nodeRecv.tagName() == QLatin1String ("starttls"))
    {
        sendData ("<proceed xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
        socket()->flush();
        socket()->startServerEncryption();
        return;
    }

    else if (ns == ns_sasl)
    {
        if (!d->passwordChecker)
        {
            warning ("Cannot perform authentication, no password checker");
            sendPacket (QXmppSaslFailure ("temporary-auth-failure"));
            disconnectFromHost();
            return;
        }

        if (nodeRecv.tagName() == QLatin1String ("auth"))
        {
            QXmppSaslAuth auth;
            auth.parse (nodeRecv);

            d->saslServer = QXmppSaslServer::create (auth.mechanism(), this);

            if (!d->saslServer)
            {
                sendPacket (QXmppSaslFailure ("invalid-mechanism"));
                disconnectFromHost();
                return;
            }

            d->saslServer->setRealm (d->domain.toUtf8());

            QByteArray challenge;
            QXmppSaslServer::Response result = d->saslServer->respond (auth.value(), challenge);

            if (result == QXmppSaslServer::InputNeeded)
            {
                // check credentials
                d->checkCredentials (auth.value());
            }

            else if (result == QXmppSaslServer::Challenge)
                sendPacket (QXmppSaslChallenge (challenge));

            else
            {
                // FIXME: what condition?
                sendPacket (QXmppSaslFailure());
                disconnectFromHost();
                return;
            }
        }

        else if (nodeRecv.tagName() == QLatin1String ("response"))
        {
            QXmppSaslResponse response;
            response.parse (nodeRecv);

            if (!d->saslServer)
            {
                warning ("SASL response received, but no mechanism selected");
                sendPacket (QXmppSaslFailure());
                disconnectFromHost();
                return;
            }

            QByteArray challenge;
            QXmppSaslServer::Response result = d->saslServer->respond (response.value(), challenge);

            if (result == QXmppSaslServer::InputNeeded)
            {
                // check credentials
                d->checkCredentials (response.value());
            }

            else if (result == QXmppSaslServer::Succeeded)
            {
                // authentication succeeded
                d->jid = QString ("%[email protected]%2").arg (d->saslServer->username(), d->domain);
                info (QString ("Authentication succeeded for '%1' from %2").arg (d->jid, d->origin()));
                updateCounter ("incoming-client.auth.success");
                sendPacket (QXmppSaslSuccess());
                handleStart();
            }

            else
            {
                // FIXME: what condition?
                sendPacket (QXmppSaslFailure());
                disconnectFromHost();
            }
        }
    }

    else if (ns == ns_client)
    {
        if (nodeRecv.tagName() == QLatin1String ("iq"))
        {
            const QString type = nodeRecv.attribute ("type");

            if (QXmppBindIq::isBindIq (nodeRecv) && type == QLatin1String ("set"))
            {
                QXmppBindIq bindSet;
                bindSet.parse (nodeRecv);
                d->resource = bindSet.resource().trimmed();

                if (d->resource.isEmpty())
                    d->resource = QXmppUtils::generateStanzaHash();

                d->jid = QString ("%1/%2").arg (QXmppUtils::jidToBareJid (d->jid), d->resource);

                QXmppBindIq bindResult;
                bindResult.setType (QXmppIq::Result);
                bindResult.setId (bindSet.id());
                bindResult.setJid (d->jid);
                sendPacket (bindResult);

                // bound
                emit connected();
                return;
            }

            else if (QXmppSessionIq::isSessionIq (nodeRecv) && type == QLatin1String ("set"))
            {
                QXmppSessionIq sessionSet;
                sessionSet.parse (nodeRecv);

                QXmppIq sessionResult;
                sessionResult.setType (QXmppIq::Result);
                sessionResult.setId (sessionSet.id());
                sessionResult.setTo (d->jid);
                sendPacket (sessionResult);
                return;
            }
        }

        // check the sender is legitimate
        const QString from = nodeRecv.attribute ("from");

        if (!from.isEmpty() && from != d->jid && from != QXmppUtils::jidToBareJid (d->jid))
        {
            warning (QString ("Received a stanza from unexpected JID %1").arg (from));
            return;
        }

        // process unhandled stanzas
        if (nodeRecv.tagName() == QLatin1String ("iq") ||
                nodeRecv.tagName() == QLatin1String ("message") ||
                nodeRecv.tagName() == QLatin1String ("presence"))
        {
            QDomElement nodeFull (nodeRecv);

            // if the sender is empty, set it to the appropriate JID
            if (nodeFull.attribute ("from").isEmpty())
            {
                if (nodeFull.tagName() == QLatin1String ("presence") &&
                        (nodeFull.attribute ("type") == QLatin1String ("subscribe") ||
                         nodeFull.attribute ("type") == QLatin1String ("subscribed")))
                    nodeFull.setAttribute ("from", QXmppUtils::jidToBareJid (d->jid));

                else
                    nodeFull.setAttribute ("from", d->jid);
            }

            // if the recipient is empty, set it to the local domain
            if (nodeFull.attribute ("to").isEmpty())
                nodeFull.setAttribute ("to", d->domain);

            // emit stanza for processing by server
            emit elementReceived (nodeFull);
        }
    }
}
Example #16
0
	void LastActivityManager::RequestLastActivity (const QString& jid)
	{
		QXmppIq iq = CreateIq (jid);
		iq.setType (QXmppIq::Get);
		client ()->sendPacket (iq);
	}
void QXmppIncomingClient::handleStanza(const QDomElement &nodeRecv)
{
    const QString ns = nodeRecv.namespaceURI();

    if (d->idleTimer->interval())
        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'><incorrect-encoding/></failure>");
                    disconnectFromHost();
                    return;
                }

                QXmppPasswordRequest request;
                request.setDomain(d->domain);
                request.setUsername(QString::fromUtf8(auth[1]));
                request.setPassword(QString::fromUtf8(auth[2]));
                if (!d->passwordChecker) {
                    // FIXME: what type of failure?
                    warning(QString("Cannot authenticate '%1', no password checker").arg(request.username()));
                    sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
                    disconnectFromHost();
                    return;
                }

                QXmppPasswordReply *reply = d->passwordChecker->checkPassword(request);
                reply->setParent(this);
                reply->setProperty("__sasl_username", request.username());
                connect(reply, SIGNAL(finished()), this, SLOT(onPasswordReply()));
            }
            else if (mechanism == "DIGEST-MD5")
            {
                // generate nonce
                d->saslDigest.setNonce(QXmppSaslDigestMd5::generateNonce());
                d->saslDigest.setQop("auth");
                d->saslStep = 1;

                QMap<QByteArray, QByteArray> challenge;
                challenge["nonce"] = d->saslDigest.nonce();
                challenge["realm"] = d->domain.toUtf8();
                challenge["qop"] = d->saslDigest.qop();
                challenge["charset"] = "utf-8";
                challenge["algorithm"] = "md5-sess";

                const QByteArray data = QXmppSaslDigestMd5::serializeMessage(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")
        {
            if (d->saslStep == 1)
            {
                const QByteArray raw = QByteArray::fromBase64(nodeRecv.text().toAscii());
                QMap<QByteArray, QByteArray> saslResponse = QXmppSaslDigestMd5::parseMessage(raw);

                // check credentials
                const QString username = QString::fromUtf8(saslResponse.value("username"));
                if (!d->passwordChecker) {
                    // FIXME: what type of failure?
                    warning(QString("Cannot authenticate '%1', no password checker").arg(username));
                    sendData("<failure xmlns='urn:ietf:params:xml:ns:xmpp-sasl'/>");
                    disconnectFromHost();
                    return;
                }

                QXmppPasswordRequest request;
                request.setUsername(username);
                request.setDomain(d->domain);

                QXmppPasswordReply *reply = d->passwordChecker->getDigest(request);
                reply->setParent(this);
                reply->setProperty("__sasl_raw", raw);
                connect(reply, SIGNAL(finished()), this, SLOT(onDigestReply()));
            }
            else if (d->saslStep == 2)
            {
                // authentication succeeded
                d->saslStep = 3;
                info(QString("Authentication succeeded for '%1'").arg(d->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 (QXmppBindIq::isBindIq(nodeRecv) && type == "set")
            {
                QXmppBindIq bindSet;
                bindSet.parse(nodeRecv);
                d->resource = bindSet.resource().trimmed();
                if (d->resource.isEmpty())
                    d->resource = generateStanzaHash();

                QXmppBindIq bindResult;
                bindResult.setType(QXmppIq::Result);
                bindResult.setId(bindSet.id());
                bindResult.setJid(jid());
                sendPacket(bindResult);

                // bound
                emit connected();
                return;
            }
            else if (QXmppSessionIq::isSessionIq(nodeRecv) && type == "set")
            {
                QXmppSessionIq sessionSet;
                sessionSet.parse(nodeRecv);

                QXmppIq sessionResult;
                sessionResult.setType(QXmppIq::Result);
                sessionResult.setId(sessionSet.id());
                sessionResult.setTo(jid());
                sendPacket(sessionResult);
                return;
            }
        }

        // check the sender is legitimate
        const QString from = nodeRecv.attribute("from");
        if (!from.isEmpty() && from != jid() && from != jidToBareJid(jid()))
        {
            warning(QString("Received a stanza from unexpected JID %1").arg(from));
            return;
        }

        // process unhandled stanzas
        if (nodeRecv.tagName() == "iq" ||
            nodeRecv.tagName() == "message" ||
            nodeRecv.tagName() == "presence")
        {
            QDomElement nodeFull(nodeRecv);

            // if the sender is empty, set it to the appropriate JID
            if (nodeFull.attribute("from").isEmpty())
            {
                if (nodeFull.tagName() == "presence" &&
                    (nodeFull.attribute("type") == "subscribe" ||
                    nodeFull.attribute("type") == "subscribed"))
                    nodeFull.setAttribute("from", jidToBareJid(jid()));
                else
                    nodeFull.setAttribute("from", jid());
            }

            // if the recipient is empty, set it to the local domain
            if (nodeFull.attribute("to").isEmpty())
                nodeFull.setAttribute("to", d->domain);

            // emit stanza for processing by server
            emit elementReceived(nodeFull);
        }
    }
}