Main Page   Namespace List   Class Hierarchy   Compound List   File List   Compound Members  

jabberoo-disco.cpp

00001 /*
00002  * jabberoo-browse.cpp
00003  * Jabber Client Library Browse Support
00004  *
00005  * Original Code Copyright (C) 1999-2001 Dave Smith (dave@jabber.org)
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public
00009  * License as published by the Free Software Foundation; either
00010  * version 2.1 of the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  *
00021  * Contributor(s): Julian Missig (IBM)
00022  *
00023  */
00024 
00025 #include "discoDB.hh"
00026 #include "session.hh"
00027 
00028 #include <sigc++/object_slot.h>
00029 
00030 namespace jabberoo {
00031 
00032     // CLASS Identity
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     // CLASS Item
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     // Hook up the callback
00142     _callbacks.insert(CallbackMap::value_type(jid, f));
00143     
00144     // Build our node
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     // Send it out
00156     _session << iq.toString().c_str();
00157 
00158     // Dupe checking and what not is handled by the xpath that picks up results
00159 }
00160 
00161 void DiscoDB::cache(const std::string& jid, const std::string& node,
00162     DiscoCallbackFunc f)
00163 {
00164     // Hook up the callback
00165     _callbacks.insert(CallbackMap::value_type(jid + "::" + node, f));
00166     
00167     // Build our node
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     // Send it out
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     // Make sure we already got the items stuff in there
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     // If we are working on a specific node we need to pull it out
00209     std::string node = query ? query->getAttrib("node") : "";
00210 
00211     // Find the one with the same node value
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     // Now we can add the identities and features
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     // Catch errors and see if we can browse instead
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     // Make our new item to insert
00271     item = new DiscoDB::Item(jid);
00272 
00273     // Clean up old entries since we are now the newest version
00274     std::pair<ItemMap::iterator, ItemMap::iterator> items = _items.equal_range(jid);
00275     _items.erase(items.first, items.second);
00276 
00277     // They don't have us at all, just pop them in
00278     _items.insert(ItemMap::value_type(jid, item));
00279     
00280     // Add any children that are there
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             // Build the child and stick it in
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                     // XXX Do something more here?  Possibly update name?
00318                 }
00319             }
00320         }
00321     }
00322             
00323     // Now we need the info element
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     // Send it out
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     // Find the first child element and ensure it has a jid
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         // XXX MAJOR ERROR HERE
00360         return;
00361     }
00362 
00363     // We need to make sure we don't already have a copy of this, if we do
00364     // clean it up and let the new one take precedence
00365         /*RL: it->mit*/
00366         DiscoDB::ItemMap::iterator mit = _items.find(jid);
00367     if (mit != _items.end())
00368     {
00369         _items.erase(mit);
00370     }
00371 
00372     // Cache it up
00373     DiscoDB::Item* item = new DiscoDB::Item(jid);
00374     // Now we add all the children and sneak in there identities
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         // This would be fubar anyway
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         // See if it's old skool
00394         if (cat.empty())
00395             cat = citem->getName();
00396         std::string type = identity->getAttrib("type");
00397         citem->addIdentity(cat, type);
00398         // See if we have namespaces to fake as features
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     // First we check all the filters
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     // See if we have a callback for this lookup
00427     std::pair<CallbackMap::iterator, CallbackMap::iterator> cis =
00428         _callbacks.equal_range(jid);
00429 
00430     if (cis.first == cis.second)
00431         return;
00432 
00433     // XXX this could be a for_each
00434     for(CallbackMap::iterator i = cis.first; i != cis.second; ++i)
00435     {
00436         i->second(item);
00437         _callbacks.erase(i);
00438     }
00439 }
00440 } // namespace jabberoo

Generated on Thu Jul 24 13:31:50 2003 for jabberoo by doxygen1.3-rc3