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

jabberoo-roster.cpp

00001 /* jabberoo-roster.cc
00002  * Jabber Roster handler
00003  *
00004  * Original Code Copyright (C) 1999-2001 Dave Smith (dave@jabber.org)
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  * 
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  * 
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  * Contributor(s): Julian Missig
00021  *
00022  * This Original Code has been modified by IBM Corporation. Modifications 
00023  * made by IBM described herein are Copyright (c) International Business 
00024  * Machines Corporation, 2002.
00025  *
00026  * Date             Modified by     Description of modification
00027  * 01/20/2002       IBM Corp.       Updated to libjudo 1.1.1
00028  * 2002-03-05       IBM Corp.       Updated to libjudo 1.1.5
00029  */
00030 
00031 #include "roster.hh"
00032 #include "judo.hpp"
00033 #include "session.hh"
00034 #include "JID.hh"
00035 #include <sigc++/object_slot.h>
00036 #include <sigc++/signal.h>
00037 
00038 namespace jabberoo {
00039 
00040 Roster::Roster(Session& s)
00041      : _owner(s)
00042 {}
00043 
00044 const Roster::Item& Roster::operator[](const std::string& jid) const
00045 {
00046      ItemMap::const_iterator it = _items.find(filterJID(jid));
00047      if (it == _items.end())
00048           throw XCP_InvalidJID();
00049      else
00050           return it->second;
00051 }
00052 
00053 Roster::Item& Roster::operator[](const std::string& jid)
00054 {
00055      ItemMap::iterator it = _items.find(filterJID(jid));
00056      if (it == _items.end())
00057           throw XCP_InvalidJID();
00058      else
00059           return it->second;
00060 }
00061 
00062 void Roster::reset()
00063 {
00064      _items.clear();
00065      evtRefresh(); // notify people that the overall Roster has been changed (emptied!)
00066 }
00067 
00068 // ---------------------------------------------------------
00069 // Information
00070 // ---------------------------------------------------------
00071 bool Roster::containsJID(const std::string& jid) const
00072 {
00073      return (_items.find(filterJID(jid)) != _items.end());
00074 }
00075 
00076 // ---------------------------------------------------------
00077 // Update ops
00078 // ---------------------------------------------------------
00079 void Roster::update(const judo::Element& t)
00080 {
00081      bool updateFlag = false;
00082 
00083      // Process each <item> tag and add/update
00084      // the roster
00085      judo::Element::const_iterator it = t.begin();
00086      for (; it != t.end(); ++it )
00087      {
00088           if ((*it)->getType() != judo::Node::ntElement)
00089                continue;
00090           // Cast item into a tag..
00091           judo::Element& item = *static_cast<judo::Element*>(*it);
00092 
00093           // Extract JID & resource
00094           std::string jid = filterJID(item.getAttrib("jid"));
00095 
00096           // Lookup this jid in the item map
00097           ItemMap::iterator rit = _items.find(jid);
00098 
00099           // If this jid is already in the Item map, update it...
00100           if (rit != _items.end())
00101           {
00102                // If the subscription type = "remove" then, we need
00103                // to delete this roster item...
00104                updateFlag = true;
00105                if (item.cmpAttrib("subscription", "remove"))
00106                {
00107                     removeItemFromAllGroups(rit->second);
00108                     _items.erase(rit);
00109                }
00110                // Otherwise, update the roster item
00111                else
00112                     rit->second.update(*this, item);
00113 
00114           }
00115           // Otherwise, create a new item on the map
00116           else if (!item.cmpAttrib("subscription", "remove"))
00117           {
00118                   _items.insert(std::make_pair(jid, Item(*this, item)));
00119                updateFlag = true;
00120           }
00121      }
00122      // Notify whoever we need to that the overall roster has been updated
00123      if (updateFlag)
00124           evtRefresh();
00125 
00126 }
00127 
00128 void Roster::update(const Presence& p, Presence::Type prev_type)
00129 {
00130      // Locate the presence sender on our map
00131      std::string jid = filterJID(p.getFrom());
00132      ItemMap::iterator it = _items.find(jid);
00133      if (it != _items.end())
00134      {
00135           it->second.update(*this, jid, p, prev_type);             // Update the item
00136      }
00137 }
00138 
00139 void Roster::update(const Item& i)
00140 {
00141      // Compose basic query packet
00142      judo::Element iq("iq");
00143      iq.putAttrib("type", "set");
00144      judo::Element* query = iq.addElement("query");
00145      query->putAttrib("xmlns", "jabber:iq:roster");
00146      judo::Element* item = query->addElement("item");
00147 
00148      // Insert item specifics
00149      item->putAttrib("jid", i.getJID());
00150      if (!i.getNickname().empty())
00151           item->putAttrib("name", i.getNickname());
00152      // Add all groups in this item
00153      for (Item::iterator it = i.begin(); it != i.end(); it++)
00154           item->addElement("group", *it);
00155 
00156      // Transmit item
00157      _owner << iq.toString().c_str();
00158 }
00159 
00160 // ---------------------------------------------------------
00161 // Control ops
00162 // ---------------------------------------------------------
00163 void Roster::deleteUser(const std::string& jid)
00164 {
00165 
00166      // Send a subscription=remove request...
00167      judo::Element iq("iq");
00168      iq.putAttrib("type", "std::set");
00169      judo::Element* query = iq.addElement("query");
00170      query->putAttrib("xmlns", "jabber:iq:roster");
00171      judo::Element* item = query->addElement("item");
00172      item->putAttrib("jid", jid);
00173      item->putAttrib("subscription", "remove");
00174 
00175      // Send it
00176      _owner << iq.toString().c_str();
00177      _owner << Presence(jid, Presence::ptUnsubRequest);
00178 
00179      // If the user is an Agent then send a remove request
00180      if ((jid.find("@") == std::string::npos) && (jid.find("/") != std::string::npos))
00181                  _owner.queryNamespace("jabber:iq:register", ::SigC::slot(*this, &Roster::deleteAgent), jid);
00182 }
00183 
00184 void Roster::deleteAgent(const judo::Element& iq)
00185 {
00186      const judo::Element* query = iq.findElement("query");
00187 
00188      judo::Element niq("iq");
00189      niq.putAttrib("type", "std::set");
00190      niq.putAttrib("to", iq.getAttrib("from"));
00191      judo::Element* nquery = niq.addElement("query");
00192      nquery->putAttrib("xmlns", "jabber:iq:register");
00193      nquery->addElement("key", query->getChildCData("key"));
00194      nquery->addElement("remove");
00195 
00196      // send iit
00197      _owner << niq.toString().c_str();
00198 }
00199 
00200 void Roster::fetch() const
00201 {
00202      judo::Element iq("iq");
00203      iq.putAttrib("type", "get");
00204      judo::Element* query = iq.addElement("query");
00205      query->putAttrib("xmlns", "jabber:iq:roster");
00206 
00207      _owner << iq.toString().c_str();
00208 }
00209 
00210 // ---------------------------------------------------------
00211 // S10N translation
00212 // ---------------------------------------------------------
00213 std::string Roster::translateS10N(Subscription stype)
00214 {
00215      switch (stype)
00216      {
00217      case rsNone:   return "none";
00218      case rsTo:     return "to";
00219      case rsFrom:   return "from";
00220      case rsBoth:   return "both";
00221      case rsRemove: return "remove";
00222      }
00223      return "none";
00224 }
00225 
00226 Roster::Subscription Roster::translateS10N(const std::string& stype)
00227 {
00228      if (stype == "to")
00229           return rsTo;
00230      else if (stype == "from")
00231           return rsFrom;
00232      else if (stype == "both")
00233           return rsBoth;
00234      else if (stype == "remove")
00235           return rsRemove;
00236      else
00237           return rsNone;
00238 }
00239 
00240 std::string Roster::filterJID(const std::string& jid)
00241 {
00242      // If this jid doesn't have a user, then
00243      // escape the whole jid and return
00244      if (jid.find("@") == std::string::npos)
00245           return judo::escape(jid);
00246      // Otherwise, escape and return just user@host
00247      else
00248           return JID::getUserHost(jid);
00249      
00250 }
00251 
00252 void Roster::removeItemFromGroup(const std::string& group, const std::string& jid)
00253 {
00254      typedef std::map<std::string, std::set<std::string> >::iterator GIT;
00255      GIT it = _groups.find(group);
00256      // Lookup this group..if found..
00257      if (it != _groups.end())
00258      {
00259           // Erase the JID in the group-std::set
00260          std::set<std::string>::iterator member = it->second.find(jid);
00261           if (member != it->second.end()) 
00262           {
00263                it->second.erase(member);
00264           } 
00265           // Erase the group-std::set if it's empty n
00266           if (it->second.empty())
00267                _groups.erase(it);
00268      }
00269 }
00270 
00271 void Roster::removeItemFromAllGroups(const Item& item)
00272 {
00273      // Remove this item from all groups
00274      for (Item::iterator it = item.begin(); it != item.end(); it++)
00275      {
00276           removeItemFromGroup(*it, item.getJID());
00277      }
00278 }
00279 
00280 void Roster::mergeItemGroups(const std::string& itemjid, const std::set<std::string>& oldgrp, const std::set<std::string>& newgrp)
00281 {
00282      // Walk the group list and update Roster::_groups
00283      // accordingly..icky..slow..wish there was a better
00284      // way
00285     std::set<std::string>::const_iterator new_it = newgrp.begin();
00286      std::set<std::string>::const_iterator old_it = oldgrp.begin();
00287      while ((new_it != newgrp.end()) || (old_it != oldgrp.end()))
00288      {
00289           if ((old_it == oldgrp.end()) && (new_it != newgrp.end()))
00290           {
00291                _groups[*new_it].insert(itemjid);
00292                ++new_it;
00293           }
00294           else if ((old_it != oldgrp.end()) && (new_it == newgrp.end()))
00295           {
00296                removeItemFromGroup(*old_it, itemjid);
00297                ++old_it;
00298           }
00299           else if ((*old_it) == (*new_it))
00300           {
00301                ++old_it; 
00302                ++new_it;
00303           }
00304           else
00305           {
00306                removeItemFromGroup(*old_it, itemjid);
00307                ++old_it;
00308           }
00309      }
00310 
00311 }
00312 
00313 // ---------------------------------------------------------
00314 // IMPLEMENTATION
00315 // 
00316 // Roster::Item
00317 // ---------------------------------------------------------
00318 Roster::Item::Item(const judo::Element& t)
00319      : _rescnt(0)
00320 {
00321      update(t);
00322 }
00323 
00324 Roster::Item::Item(Roster& r, const judo::Element& t)
00325      : _rescnt(0)
00326 {
00327      update(r, t);
00328 }
00329 
00330 Roster::Item::Item(const std::string& jid, const std::string& nickname)
00331      : _jid(jid), _nickname(nickname)
00332 {}
00333 
00334 Roster::Item::~Item()
00335 {}
00336 
00337 void Roster::Item::addToGroup(const std::string& group)
00338 {
00339      _groups.insert(group);
00340 }
00341 
00342 void Roster::Item::delFromGroup(const std::string& group)
00343 {
00344      _groups.erase(group);
00345 }
00346 
00347 void Roster::Item::clearGroups()
00348 {
00349      _groups.clear();
00350 }
00351 
00352 bool Roster::Item::update(const judo::Element& t)
00353 {
00354      _jid = t.getAttrib("jid");
00355 
00356      // If no nickname is available, use standard user@host
00357      _nickname = t.getAttrib("name");
00358      if (_nickname == "")
00359           _nickname = _jid;
00360           
00361      // Get subscription
00362      _type = Roster::translateS10N(t.getAttrib("subscription"));    
00363      
00364      // Determine if subscription is pending
00365      _pending = (t.getAttrib("ask") == "subscribe");
00366 
00367      _groups.clear();
00368      
00369      // Parse group std::set from subtags
00370      judo::Element::const_iterator it = t.begin();
00371      for (; it != t.end(); ++it)
00372      {
00373           if ((*it)->getType() != judo::Node::ntElement)
00374                continue;
00375           std::string grp_name = static_cast<judo::Element*>(*it)->getCDATA();
00376           if (!grp_name.empty())
00377                _groups.insert(grp_name);
00378      }
00379 
00380      // If the subscription is pending, also display them in Pending virtual group
00381      if (_pending)
00382      {
00383           _groups.insert("Pending");
00384      }
00385      // If they're not in a group, display them in Unfiled virtual group
00386      else if (_groups.empty())
00387      {
00388           // If this jid has no user, but *does* have a resource,
00389           // it must be an agent/transport registration
00390           if ((_jid.find("@") == std::string::npos) && (_jid.find("/") != std::string::npos))
00391                _groups.insert("Agents");
00392           // Otherwise, it should be displayed in Unfiled
00393           else
00394                _groups.insert("Unfiled");
00395      }
00396 
00397      return true;
00398 }
00399 
00400 bool Roster::Item::update(Roster& r, const judo::Element& t)
00401 {
00402      // Save old group std::set
00403      std::set<std::string> oldGroups = _groups;
00404 
00405      update(t);
00406 
00407      // Have the owner merge it's representation of item groups
00408      // appropriately
00409      r.mergeItemGroups(_jid, oldGroups, _groups);
00410 
00411      return true;
00412 }
00413 
00414 void Roster::Item::update(Roster& r, const std::string& jid, const Presence& p, Presence::Type prev_type)
00415 {
00416      bool available = r._owner.presenceDB().available(jid);
00417      
00418      if ((available == true) && (_rescnt == 0))
00419      {
00420           ++_rescnt;
00421      }
00422      else if ((available == false) && (_rescnt == 1))
00423      {
00424           --_rescnt;
00425      }
00426      r.evtPresence(jid, (_rescnt != 0), prev_type);
00427 }
00428 
00429 bool Roster::Item::isAvailable() const
00430 {
00431      return (_rescnt > 0);
00432 }
00433 
00434 std::string Roster::Item::getNickname() const
00435 {
00436      return _nickname;
00437 }
00438 
00439 void Roster::Item::setNickname(const std::string& nickname)
00440 {
00441      _nickname = nickname;
00442 }
00443 
00444 std::string Roster::Item::getJID() const
00445 {
00446      return _jid;
00447 }
00448 
00449 void Roster::Item::setJID(const std::string& jid)
00450 {
00451      _jid = jid;
00452 }
00453 
00454 Roster::Subscription Roster::Item::getSubsType() const
00455 {
00456      return _type;
00457 }
00458 
00459 bool Roster::Item::isPending() const
00460 {
00461      return _pending;
00462 }
00463 
00464 }

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