void QXmppIncomingServer::handleStanza(const QDomElement &stanza) { const QString ns = stanza.namespaceURI(); if (ns == ns_tls && stanza.tagName() == QLatin1String("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(QString("Invalid dialback received on %1").arg(d->origin())); return; } const QString domain = request.from(); if (request.command() == QXmppDialback::Result) { debug(QString("Received a dialback result from '%1' on %2").arg(domain, d->origin())); // establish dialback connection QXmppOutgoingServer *stream = new QXmppOutgoingServer(d->domain, this); bool check = connect(stream, SIGNAL(dialbackResponseReceived(QXmppDialback)), this, SLOT(slotDialbackResponseReceived(QXmppDialback))); Q_ASSERT(check); Q_UNUSED(check); stream->setVerify(d->localStreamId, request.key()); stream->connectToHost(domain); } else if (request.command() == QXmppDialback::Verify) { debug(QString("Received a dialback verify from '%1' on %2").arg(domain, d->origin())); emit dialbackRequestReceived(request); } } else if (d->authenticated.contains(QXmppUtils::jidToDomain(stanza.attribute("from")))) { // relay stanza if the remote party is authenticated emit elementReceived(stanza); } else { warning(QString("Received an element from unverified domain '%1' on %2").arg(QXmppUtils::jidToDomain(stanza.attribute("from")), d->origin())); disconnectFromHost(); } }
void QXmppIncomingServer::slotDialbackResponseReceived(const QXmppDialback &dialback) { QXmppOutgoingServer *stream = qobject_cast<QXmppOutgoingServer*>(sender()); if (!stream || dialback.command() != QXmppDialback::Verify || dialback.id() != d->localStreamId || dialback.from() != stream->remoteDomain()) 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() == QLatin1String("valid")) { info(QString("Verified incoming domain '%1' on %2").arg(dialback.from(), d->origin())); const bool wasConnected = !d->authenticated.isEmpty(); d->authenticated.insert(dialback.from()); if (!wasConnected) emit connected(); } else { warning(QString("Failed to verify incoming domain '%1' on %2").arg(dialback.from(), d->origin())); disconnectFromHost(); } // disconnect dialback stream->disconnectFromHost(); stream->deleteLater(); }
void QXmppOutgoingServer::handleStanza(const QDomElement &stanza) { const QString ns = stanza.namespaceURI(); if(QXmppStreamFeatures::isStreamFeatures(stanza)) { QXmppStreamFeatures features; features.parse(stanza); if (!socket()->isEncrypted()) { // check we can satisfy TLS constraints if (!socket()->supportsSsl() && features.tlsMode() == QXmppStreamFeatures::Required) { warning("Disconnecting as TLS is required, but SSL support is not available"); disconnectFromHost(); return; } // enable TLS if possible if (socket()->supportsSsl() && features.tlsMode() != QXmppStreamFeatures::Disabled) { sendData("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); return; } } // send dialback if needed d->dialbackTimer->stop(); sendDialback(); } else if (ns == ns_tls) { if (stanza.tagName() == QLatin1String("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->localDomain || response.type().isEmpty()) { warning("Invalid dialback response received"); return; } if (response.command() == QXmppDialback::Result) { if (response.type() == QLatin1String("valid")) { info(QString("Outgoing server stream to %1 is ready").arg(response.from())); d->ready = true; // send queued data Q_FOREACH (const QByteArray &data, d->dataQueue) sendData(data); d->dataQueue.clear(); // emit signal Q_EMIT connected(); } } else if (response.command() == QXmppDialback::Verify)