00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "discoDB.hh"
00026 #include "session.hh"
00027
00028 #include <sigc++/object_slot.h>
00029
00030 namespace jabberoo {
00031
00032
00033 DiscoDB::Item::Identity::Identity(const judo::Element& e)
00034 {
00035 _type = e.getAttrib("type");
00036 _category = e.getAttrib("category");
00037 }
00038
00039 DiscoDB::Item::Identity::Identity(const std::string& category, const std::string& type):
00040 _category(category), _type(type)
00041 { }
00042
00043 DiscoDB::Item::Identity::~Identity()
00044 { }
00045
00046 const std::string& DiscoDB::Item::Identity::getType() const
00047 { return _type; }
00048
00049 const std::string& DiscoDB::Item::Identity::getCategory() const
00050 { return _category; }
00051
00052
00053
00054 DiscoDB::Item::~Item()
00055 {
00056 while(!_identities.empty())
00057 {
00058 DiscoDB::Item::Identity* ident = _identities.front();
00059 delete ident;
00060 _identities.pop_front();
00061 }
00062 }
00063
00064 DiscoDB::Item::Item(const std::string& jid) : _jid(jid)
00065 { }
00066
00067 const std::string& DiscoDB::Item::getJID() const
00068 { return _jid; }
00069
00070 void DiscoDB::Item::setNode(const std::string& val)
00071 { _node = val; }
00072
00073 const std::string& DiscoDB::Item::getNode() const
00074 { return _node; }
00075
00076 void DiscoDB::Item::setName(const std::string& val)
00077 { _name = val; }
00078
00079 const std::string& DiscoDB::Item::getName() const
00080 { return _name; }
00081
00082 const DiscoDB::Item::IdentityList& DiscoDB::Item::getIdentityList() const
00083 { return _identities; }
00084
00085 const DiscoDB::Item::FeatureList& DiscoDB::Item::getFeatureList() const
00086 { return _features; }
00087
00088 bool DiscoDB::Item::hasChildren()
00089 { return (_children.size() > 0); }
00090
00091 DiscoDB::Item::iterator DiscoDB::Item::begin()
00092 { return _children.begin(); }
00093
00094 DiscoDB::Item::const_iterator DiscoDB::Item::begin() const
00095 { return _children.begin(); }
00096
00097 DiscoDB::Item::iterator DiscoDB::Item::end()
00098 { return _children.end(); }
00099
00100 DiscoDB::Item::const_iterator DiscoDB::Item::end() const
00101 { return _children.end(); }
00102
00103 void DiscoDB::Item::appendChild(DiscoDB::Item* item)
00104 { _children.push_back(item); }
00105
00106 void DiscoDB::Item::addFeature(const std::string& feature)
00107 { _features.push_back(feature); }
00108
00109 void DiscoDB::Item::addIdentity(const judo::Element& e)
00110 { _identities.push_back(new Identity(e)); }
00111
00112 void DiscoDB::Item::addIdentity(const std::string& category,
00113 const std::string& type)
00114 { _identities.push_back(new Identity(category, type)); }
00115
00116
00117
00118 DiscoDB::DiscoDB(Session& sess) :
00119 _session(sess)
00120 {
00121 }
00122
00123 DiscoDB::~DiscoDB()
00124 {
00125 clear();
00126 }
00127
00128 DiscoDB::Item& DiscoDB::operator[](const std::string& jid)
00129 {
00130 DiscoDB::iterator it = _items.find(jid);
00131 if (it == _items.end())
00132 {
00133 throw XCP_NotCached();
00134 }
00135
00136 return *(it->second);
00137 }
00138
00139 void DiscoDB::cache(const std::string& jid, DiscoCallbackFunc f)
00140 {
00141
00142 _callbacks.insert(CallbackMap::value_type(jid, f));
00143
00144
00145 judo::Element iq("iq");
00146 iq.putAttrib("type", "get");
00147 std::string id = _session.getNextID();
00148 iq.putAttrib("id", id);
00149 iq.putAttrib("to", jid);
00150 judo::Element* query = iq.addElement("query");
00151 query->putAttrib("xmlns", "http://jabber.org/protocol/disco#items");
00152
00153 _session.registerIQ(id, SigC::slot(*this, &DiscoDB::discoItemsCB));
00154
00155
00156 _session << iq.toString().c_str();
00157
00158
00159 }
00160
00161 void DiscoDB::cache(const std::string& jid, const std::string& node,
00162 DiscoCallbackFunc f)
00163 {
00164
00165 _callbacks.insert(CallbackMap::value_type(jid + "::" + node, f));
00166
00167
00168 judo::Element iq("iq");
00169 iq.putAttrib("type", "get");
00170 std::string id = _session.getNextID();
00171 iq.putAttrib("id", id);
00172 iq.putAttrib("to", jid);
00173 judo::Element* query = iq.addElement("query");
00174 query->putAttrib("xmlns", "http://jabber.org/protocol/disco#items");
00175 query->putAttrib("node", node);
00176
00177 _session.registerIQ(id, SigC::slot(*this, &DiscoDB::discoInfoCB));
00178
00179
00180 _session << iq.toString().c_str();
00181 }
00182
00183 void DiscoDB::clear()
00184 {
00185 for (DiscoDB::iterator it = _items.begin(); it != _items.end(); ++it)
00186 {
00187 delete it->second;
00188 }
00189
00190 _items.clear();
00191 }
00192
00193 void DiscoDB::discoInfoCB(const judo::Element& e)
00194 {
00195 std::string jid = e.getAttrib("from");
00196
00197
00198 std::pair<ItemMap::iterator, ItemMap::iterator> items = _items.equal_range(jid);
00199 if (items.first == items.second)
00200 {
00201 runCallbacks(jid, NULL);
00202 return;
00203 }
00204 DiscoDB::Item* item = NULL;
00205
00206 const judo::Element* query = e.findElement("query");
00207
00208
00209 std::string node = query ? query->getAttrib("node") : "";
00210
00211
00212 for (ItemMap::iterator i = items.first; i != items.second; ++i)
00213 {
00214 if (i->second->getNode() == node)
00215 {
00216 item = i->second;
00217 break;
00218 }
00219 }
00220
00221
00222 for (judo::Element::const_iterator it = query->begin(); it != query->end(); ++it)
00223 {
00224 if ((*it)->getType() == judo::Node::ntElement)
00225 {
00226 judo::Element* elem = static_cast<judo::Element*>((*it));
00227 std::string name = elem->getName();
00228 if (name == "feature")
00229 {
00230 std::string feature = elem->getAttrib("var");
00231 if (!feature.empty())
00232 item->addFeature(feature);
00233 }
00234 else if (name == "identity")
00235 {
00236 item->addIdentity(*elem);
00237 }
00238 }
00239 }
00240
00241 runCallbacks(jid, item);
00242 }
00243
00244 void DiscoDB::discoItemsCB(const judo::Element& e)
00245 {
00246 std::string type = e.getAttrib("type");
00247 std::string jid = e.getAttrib("from");
00248
00249
00250 if (type == "error")
00251 {
00252 judo::Element iq("iq");
00253 iq.putAttrib("type", "get");
00254 std::string id = _session.getNextID();
00255 iq.putAttrib("id", id);
00256 iq.putAttrib("to", jid);
00257 judo::Element* item_query = iq.addElement("item");
00258 item_query->putAttrib("xmlns", "jabber:iq:browse");
00259
00260 _session.registerIQ(id, SigC::slot(*this, &DiscoDB::browseCB));
00261
00262 jabberoo::Packet pkt(iq);
00263 _session << pkt;
00264
00265 return;
00266 }
00267
00268 DiscoDB::Item *item = NULL;
00269
00270
00271 item = new DiscoDB::Item(jid);
00272
00273
00274 std::pair<ItemMap::iterator, ItemMap::iterator> items = _items.equal_range(jid);
00275 _items.erase(items.first, items.second);
00276
00277
00278 _items.insert(ItemMap::value_type(jid, item));
00279
00280
00281 const judo::Element* query = e.findElement("query");
00282 std::string node = query ? query->getAttrib("node") : "";
00283 if (!node.empty())
00284 item->setNode(node);
00285
00286 if (query)
00287 {
00288 for (judo::Element::const_iterator it = query->begin();
00289 it != query->end(); ++it)
00290 {
00291 if ( (*it)->getType() != judo::Node::ntElement )
00292 {
00293 continue;
00294 }
00295
00296
00297 judo::Element* elem = static_cast<judo::Element*>(*it);
00298 if (elem->getName() == "item")
00299 {
00300 std::string cjid = elem->getAttrib("jid");
00301 std::string cname = elem->getAttrib("name");
00302 std::string cnode = elem->getAttrib("node");
00303 DiscoDB::Item* child = NULL;
00304 DiscoDB::iterator nit = _items.find(cjid);
00305 if (nit == _items.end())
00306 {
00307 child = new DiscoDB::Item(cjid);
00308 if (!cname.empty())
00309 child->setName(cname);
00310 if (!cnode.empty())
00311 child->setNode(cnode);
00312 _items.insert(ItemMap::value_type(cjid, child));
00313 item->appendChild(child);
00314 }
00315 else
00316 {
00317
00318 }
00319 }
00320 }
00321 }
00322
00323
00324 judo::Element iq("iq");
00325 iq.putAttrib("type", "get");
00326 std::string id = _session.getNextID();
00327 iq.putAttrib("id", id);
00328 iq.putAttrib("to", jid);
00329 judo::Element* info_query = iq.addElement("query");
00330 info_query->putAttrib("xmlns", "http://jabber.org/protocol/disco#info");
00331 if (!node.empty())
00332 info_query->putAttrib("node", node);
00333
00334 _session.registerIQ(id, SigC::slot(*this, &DiscoDB::discoInfoCB));
00335
00336
00337 _session << iq.toString().c_str();
00338 }
00339
00340 void DiscoDB::browseCB(const judo::Element& e)
00341 {
00342 judo::Element* child = NULL;
00343 std::string jid;
00344
00345
00346 for (judo::Element::const_iterator it = e.begin(); it != e.end(); ++it)
00347 {
00348 if ( (*it)->getType() == judo::Node::ntElement )
00349 {
00350 child = static_cast<judo::Element*>(*it);
00351 jid = child->getAttrib("jid");
00352 if (!jid.empty())
00353 break;
00354 }
00355 }
00356
00357 if (child == NULL)
00358 {
00359
00360 return;
00361 }
00362
00363
00364
00365
00366 DiscoDB::ItemMap::iterator mit = _items.find(jid);
00367 if (mit != _items.end())
00368 {
00369 _items.erase(mit);
00370 }
00371
00372
00373 DiscoDB::Item* item = new DiscoDB::Item(jid);
00374
00375 judo::Element* identity;
00376 for (judo::Element::iterator i = child->begin(); i != child->end(); ++i)
00377 {
00378 if ( (*i)->getType() != judo::Node::ntElement )
00379 {
00380 continue;
00381 }
00382
00383 identity = static_cast<judo::Element*>(*i);
00384 std::string cjid = identity->getAttrib("jid");
00385
00386 if (cjid.empty())
00387 continue;
00388
00389 DiscoDB::Item* citem = new DiscoDB::Item(cjid);
00390 citem->setName(identity->getAttrib("name"));
00391 item->appendChild(citem);
00392 std::string cat = identity->getAttrib("category");
00393
00394 if (cat.empty())
00395 cat = citem->getName();
00396 std::string type = identity->getAttrib("type");
00397 citem->addIdentity(cat, type);
00398
00399 for (judo::Element::iterator nsi = identity->begin();
00400 nsi != identity->end(); ++nsi)
00401 {
00402 if ( ((*i)->getType() == judo::Node::ntElement) &&
00403 ((*i)->getName() == "ns") )
00404 {
00405 judo::Element* ns = static_cast<judo::Element*>(*i);
00406 citem->addFeature(ns->getCDATA());
00407 }
00408 }
00409 }
00410 _items.insert(ItemMap::value_type(jid, item));
00411
00412 runCallbacks(jid, item);
00413 }
00414
00415 void DiscoDB::runCallbacks(const std::string& jid, const DiscoDB::Item* item)
00416 {
00417
00418 for (FilterMap::iterator i = _filters.begin(); i != _filters.end(); ++i)
00419 {
00420 if ((*i)->pred_(*item))
00421 {
00422 (*i)->jid_list_.push_back(jid);
00423 }
00424 }
00425
00426
00427 std::pair<CallbackMap::iterator, CallbackMap::iterator> cis =
00428 _callbacks.equal_range(jid);
00429
00430 if (cis.first == cis.second)
00431 return;
00432
00433
00434 for(CallbackMap::iterator i = cis.first; i != cis.second; ++i)
00435 {
00436 i->second(item);
00437 _callbacks.erase(i);
00438 }
00439 }
00440 }