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
00026
00027
00028
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();
00066 }
00067
00068
00069
00070
00071 bool Roster::containsJID(const std::string& jid) const
00072 {
00073 return (_items.find(filterJID(jid)) != _items.end());
00074 }
00075
00076
00077
00078
00079 void Roster::update(const judo::Element& t)
00080 {
00081 bool updateFlag = false;
00082
00083
00084
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
00091 judo::Element& item = *static_cast<judo::Element*>(*it);
00092
00093
00094 std::string jid = filterJID(item.getAttrib("jid"));
00095
00096
00097 ItemMap::iterator rit = _items.find(jid);
00098
00099
00100 if (rit != _items.end())
00101 {
00102
00103
00104 updateFlag = true;
00105 if (item.cmpAttrib("subscription", "remove"))
00106 {
00107 removeItemFromAllGroups(rit->second);
00108 _items.erase(rit);
00109 }
00110
00111 else
00112 rit->second.update(*this, item);
00113
00114 }
00115
00116 else if (!item.cmpAttrib("subscription", "remove"))
00117 {
00118 _items.insert(std::make_pair(jid, Item(*this, item)));
00119 updateFlag = true;
00120 }
00121 }
00122
00123 if (updateFlag)
00124 evtRefresh();
00125
00126 }
00127
00128 void Roster::update(const Presence& p, Presence::Type prev_type)
00129 {
00130
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);
00136 }
00137 }
00138
00139 void Roster::update(const Item& i)
00140 {
00141
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
00149 item->putAttrib("jid", i.getJID());
00150 if (!i.getNickname().empty())
00151 item->putAttrib("name", i.getNickname());
00152
00153 for (Item::iterator it = i.begin(); it != i.end(); it++)
00154 item->addElement("group", *it);
00155
00156
00157 _owner << iq.toString().c_str();
00158 }
00159
00160
00161
00162
00163 void Roster::deleteUser(const std::string& jid)
00164 {
00165
00166
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
00176 _owner << iq.toString().c_str();
00177 _owner << Presence(jid, Presence::ptUnsubRequest);
00178
00179
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
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
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
00243
00244 if (jid.find("@") == std::string::npos)
00245 return judo::escape(jid);
00246
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
00257 if (it != _groups.end())
00258 {
00259
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
00266 if (it->second.empty())
00267 _groups.erase(it);
00268 }
00269 }
00270
00271 void Roster::removeItemFromAllGroups(const Item& item)
00272 {
00273
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
00283
00284
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
00315
00316
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
00357 _nickname = t.getAttrib("name");
00358 if (_nickname == "")
00359 _nickname = _jid;
00360
00361
00362 _type = Roster::translateS10N(t.getAttrib("subscription"));
00363
00364
00365 _pending = (t.getAttrib("ask") == "subscribe");
00366
00367 _groups.clear();
00368
00369
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
00381 if (_pending)
00382 {
00383 _groups.insert("Pending");
00384 }
00385
00386 else if (_groups.empty())
00387 {
00388
00389
00390 if ((_jid.find("@") == std::string::npos) && (_jid.find("/") != std::string::npos))
00391 _groups.insert("Agents");
00392
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
00403 std::set<std::string> oldGroups = _groups;
00404
00405 update(t);
00406
00407
00408
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 }