1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
/*
* Copyright (c) 2010 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#include <Swift/Controllers/DiscoServiceWalker.h>
#include <boost/bind.hpp>
#include "Swiften/Disco/GetDiscoInfoRequest.h"
#include "Swiften/Disco/GetDiscoItemsRequest.h"
namespace Swift {
DiscoServiceWalker::DiscoServiceWalker(const JID& service, IQRouter* iqRouter, size_t maxSteps) : service_(service), iqRouter_(iqRouter), maxSteps_(maxSteps) {
}
void DiscoServiceWalker::beginWalk() {
assert(servicesBeingSearched_.size() == 0);
walkNode(service_);
}
void DiscoServiceWalker::walkNode(const JID& jid) {
servicesBeingSearched_.push_back(jid);
searchedServices_.push_back(jid);
GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(jid, iqRouter_);
discoInfoRequest->onResponse.connect(boost::bind(&DiscoServiceWalker::handleDiscoInfoResponse, this, _1, _2, jid));
discoInfoRequest->send();
}
void DiscoServiceWalker::handleReceivedDiscoItem(const JID& item) {
if (std::find(searchedServices_.begin(), searchedServices_.end(), item) != searchedServices_.end()) {
/* Don't recurse infinitely */
return;
}
walkNode(item);
}
void DiscoServiceWalker::handleDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error, const JID& jid) {
if (error) {
handleDiscoError(jid, error);
return;
}
bool couldContainServices = false;
foreach (DiscoInfo::Identity identity, info->getIdentities()) {
if (identity.getCategory() == "server") {
couldContainServices = true;
}
}
bool completed = false;
if (couldContainServices) {
GetDiscoItemsRequest::ref discoItemsRequest = GetDiscoItemsRequest::create(jid, iqRouter_);
discoItemsRequest->onResponse.connect(boost::bind(&DiscoServiceWalker::handleDiscoItemsResponse, this, _1, _2, jid));
discoItemsRequest->send();
} else {
completed = true;
}
onServiceFound(jid, info);
if (completed) {
markNodeCompleted(jid);
}
}
void DiscoServiceWalker::handleDiscoItemsResponse(boost::shared_ptr<DiscoItems> items, ErrorPayload::ref error, const JID& jid) {
if (error) {
handleDiscoError(jid, error);
return;
}
foreach (DiscoItems::Item item, items->getItems()) {
if (item.getNode().isEmpty()) {
/* Don't look at noded items. It's possible that this will exclude some services,
* but I've never seen one in the wild, and it's an easy fix for not looping.
*/
handleReceivedDiscoItem(item.getJID());
}
}
markNodeCompleted(jid);
}
void DiscoServiceWalker::handleDiscoError(const JID& jid, ErrorPayload::ref /*error*/) {
markNodeCompleted(jid);
}
void DiscoServiceWalker::markNodeCompleted(const JID& jid) {
servicesBeingSearched_.erase(std::remove(servicesBeingSearched_.begin(), servicesBeingSearched_.end(), jid), servicesBeingSearched_.end());
/* All results are in */
if (servicesBeingSearched_.size() == 0) {
onWalkComplete();
}
/* Check if we're on a rampage */
if (searchedServices_.size() >= maxSteps_) {
onWalkComplete();
}
}
}
|