void ServerInfoStorage::HandleItemInfo (const QXmppDiscoveryIq& iq) { auto hasIdentity = [&iq] (const QString& cat, const QString& type) -> bool { const auto& ids = iq.identities (); return std::any_of (ids.begin (), ids.end (), [&cat, &type] (const auto& id) { return id.category () == cat && id.type () == type; }); }; if (hasIdentity ("proxy", "bytestreams")) { BytestreamsProxy_ = iq.from (); emit bytestreamsProxyChanged (BytestreamsProxy_); } }
void ServerInfoStorage::HandleItems (const QXmppDiscoveryIq& iq) { for (const auto& item : iq.items ()) Conn_->GetDiscoManagerWrapper ()->RequestInfo (item.jid (), [this] (const QXmppDiscoveryIq& iq) { HandleItemInfo (iq); }, false, item.node ()); }
void tst_QXmppDiscoveryIq::testDiscovery() { const QByteArray xml( "<iq id=\"disco1\" from=\"[email protected]/230193\" type=\"result\">" "<query xmlns=\"http://jabber.org/protocol/disco#info\">" "<identity category=\"client\" name=\"Exodus 0.9.1\" type=\"pc\"/>" "<feature var=\"http://jabber.org/protocol/caps\"/>" "<feature var=\"http://jabber.org/protocol/disco#info\"/>" "<feature var=\"http://jabber.org/protocol/disco#items\"/>" "<feature var=\"http://jabber.org/protocol/muc\"/>" "</query>" "</iq>"); QXmppDiscoveryIq disco; parsePacket(disco, xml); QCOMPARE(disco.verificationString(), QByteArray::fromBase64("QgayPKawpkPSDYmwT/WM94uAlu0=")); serializePacket(disco, xml); }
void ChatClient::_q_discoveryItemsReceived(const QXmppDiscoveryIq &disco) { // we only want results if (!d->discoQueue.removeAll(disco.id()) || disco.type() != QXmppIq::Result) return; if (disco.from() == configuration().domain() && disco.queryNode().isEmpty()) { // root items foreach (const QXmppDiscoveryIq::Item &item, disco.items()) { if (!item.jid().isEmpty() && item.node().isEmpty()) { // get info for item const QString id = d->discoManager->requestInfo(item.jid(), item.node()); if (!id.isEmpty()) d->discoQueue.append(id); } } }
void tst_QXmppDiscoveryIq::testDiscoveryWithForm() { const QByteArray xml( "<iq id=\"disco1\" to=\"[email protected]/chamber\" from=\"[email protected]/230193\" type=\"result\">" "<query xmlns=\"http://jabber.org/protocol/disco#info\" node=\"http://psi-im.org#q07IKJEyjvHSyhy//CH0CxmKi8w=\">" "<identity xml:lang=\"en\" category=\"client\" name=\"Psi 0.11\" type=\"pc\"/>" "<identity xml:lang=\"el\" category=\"client\" name=\"Ψ 0.11\" type=\"pc\"/>" "<feature var=\"http://jabber.org/protocol/caps\"/>" "<feature var=\"http://jabber.org/protocol/disco#info\"/>" "<feature var=\"http://jabber.org/protocol/disco#items\"/>" "<feature var=\"http://jabber.org/protocol/muc\"/>" "<x xmlns=\"jabber:x:data\" type=\"result\">" "<field type=\"hidden\" var=\"FORM_TYPE\">" "<value>urn:xmpp:dataforms:softwareinfo</value>" "</field>" "<field type=\"text-multi\" var=\"ip_version\">" "<value>ipv4</value>" "<value>ipv6</value>" "</field>" "<field type=\"text-single\" var=\"os\">" "<value>Mac</value>" "</field>" "<field type=\"text-single\" var=\"os_version\">" "<value>10.5.1</value>" "</field>" "<field type=\"text-single\" var=\"software\">" "<value>Psi</value>" "</field>" "<field type=\"text-single\" var=\"software_version\">" "<value>0.11</value>" "</field>" "</x>" "</query>" "</iq>"); QXmppDiscoveryIq disco; parsePacket(disco, xml); QCOMPARE(disco.verificationString(), QByteArray::fromBase64("q07IKJEyjvHSyhy//CH0CxmKi8w=")); serializePacket(disco, xml); }
QXmppDiscoveryIq QXmppDiscoveryManager::capabilities() { QXmppDiscoveryIq iq; iq.setType(QXmppIq::Result); iq.setQueryType(QXmppDiscoveryIq::InfoQuery); // features QStringList features; features << ns_chat_states // XEP-0085: Chat State Notifications << ns_capabilities // XEP-0115 : Entity Capabilities << ns_ping // XEP-0199: XMPP Ping << ns_attention; // XEP-0224: Attention foreach(QXmppClientExtension* extension, client()->extensions()) { if(extension) features << extension->discoveryFeatures(); } iq.setFeatures(features); // identities QList<QXmppDiscoveryIq::Identity> identities; QXmppDiscoveryIq::Identity identity; identity.setCategory(clientCategory()); identity.setType(clientType()); identity.setName(clientName()); identities << identity; foreach(QXmppClientExtension* extension, client()->extensions()) { if(extension) identities << extension->discoveryIdentities(); } iq.setIdentities(identities); return iq; }
QString QXmppDiscoveryManager::requestInfo(const QString& jid, const QString& node) { QXmppDiscoveryIq request; request.setType(QXmppIq::Get); request.setQueryType(QXmppDiscoveryIq::InfoQuery); request.setTo(jid); if(!node.isEmpty()) request.setQueryNode(node); if(client()->sendPacket(request)) return request.id(); else return QString(); }
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; }
void ChatClient::_q_discoveryInfoReceived(const QXmppDiscoveryIq &disco) { // we only want results if (!d->discoQueue.removeAll(disco.id()) || disco.type() != QXmppIq::Result) return; foreach (const QXmppDiscoveryIq::Identity &id, disco.identities()) { // check if it's a conference server if (id.category() == QLatin1String("conference") && id.type() == QLatin1String("text")) { d->mucServer = disco.from(); info("Found chat room server " + d->mucServer); emit mucServerChanged(d->mucServer); } // check if it's a diagnostics server else if (id.category() == QLatin1String("diagnostics") && id.type() == QLatin1String("server")) { d->diagnosticServer = disco.from(); info("Found diagnostics server " + d->diagnosticServer); emit diagnosticServerChanged(d->diagnosticServer); } #if 0 // check if it's a publish-subscribe server else if (id.category() == QLatin1String("pubsub") && id.type() == QLatin1String("service")) { d->pubSubServer = disco.from(); info("Found pubsub server " + d->pubSubServer); emit pubSubServerChanged(d->pubSubServer); } #endif // check if it's a SOCKS5 proxy server else if (id.category() == QLatin1String("proxy") && id.type() == QLatin1String("bytestreams")) { info("Found bytestream proxy " + disco.from()); QXmppTransferManager *transferManager = findExtension<QXmppTransferManager>(); if (transferManager) transferManager->setProxy(disco.from()); } // check if it's a file sharing server else if (id.category() == QLatin1String("store") && id.type() == QLatin1String("file")) { d->shareServer = disco.from(); info("Found share server " + d->shareServer); emit shareServerChanged(d->shareServer); } } // if it's the root server, ask for items if (disco.from() == configuration().domain() && disco.queryNode().isEmpty()) { const QString id = d->discoManager->requestItems(disco.from(), disco.queryNode()); if (!id.isEmpty()) d->discoQueue.append(id); } }
bool QXmppDiscoveryManager::handleStanza(const QDomElement &element) { if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element)) { QXmppDiscoveryIq receivedIq; receivedIq.parse(element); if(receivedIq.type() == QXmppIq::Get && receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery && (receivedIq.queryNode().isEmpty() || receivedIq.queryNode().startsWith(d->clientCapabilitiesNode))) { // respond to query QXmppDiscoveryIq qxmppFeatures = capabilities(); qxmppFeatures.setId(receivedIq.id()); qxmppFeatures.setTo(receivedIq.from()); qxmppFeatures.setQueryNode(receivedIq.queryNode()); client()->sendPacket(qxmppFeatures); } else if(receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery) emit infoReceived(receivedIq); else if(receivedIq.queryType() == QXmppDiscoveryIq::ItemsQuery) emit itemsReceived(receivedIq); return true; } return false; }