QXmppRosterManager.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. /*
  2. * Copyright (C) 2008-2012 The QXmpp developers
  3. *
  4. * Authors:
  5. * Manjeet Dahiya
  6. * Jeremy Lainé
  7. *
  8. * Source:
  9. * http://code.google.com/p/qxmpp
  10. *
  11. * This file is a part of QXmpp library.
  12. *
  13. * This library is free software; you can redistribute it and/or
  14. * modify it under the terms of the GNU Lesser General Public
  15. * License as published by the Free Software Foundation; either
  16. * version 2.1 of the License, or (at your option) any later version.
  17. *
  18. * This library is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  21. * Lesser General Public License for more details.
  22. *
  23. */
  24. #include <QDomElement>
  25. #include "QXmppClient.h"
  26. #include "QXmppPresence.h"
  27. #include "QXmppRosterIq.h"
  28. #include "QXmppRosterManager.h"
  29. #include "QXmppUtils.h"
  30. class QXmppRosterManagerPrivate
  31. {
  32. public:
  33. QXmppRosterManagerPrivate(QXmppRosterManager *qq);
  34. // map of bareJid and its rosterEntry
  35. QMap<QString, QXmppRosterIq::Item> entries;
  36. // map of resources of the jid and map of resources and presences
  37. QMap<QString, QMap<QString, QXmppPresence> > presences;
  38. // flag to store that the roster has been populated
  39. bool isRosterReceived;
  40. // id of the initial roster request
  41. QString rosterReqId;
  42. private:
  43. QXmppRosterManager *q;
  44. };
  45. QXmppRosterManagerPrivate::QXmppRosterManagerPrivate(QXmppRosterManager *qq)
  46. : isRosterReceived(false),
  47. q(qq)
  48. {
  49. }
  50. /// Constructs a roster manager.
  51. QXmppRosterManager::QXmppRosterManager(QXmppClient* client)
  52. {
  53. bool check;
  54. Q_UNUSED(check);
  55. d = new QXmppRosterManagerPrivate(this);
  56. check = connect(client, SIGNAL(connected()),
  57. this, SLOT(_q_connected()));
  58. Q_ASSERT(check);
  59. check = connect(client, SIGNAL(disconnected()),
  60. this, SLOT(_q_disconnected()));
  61. Q_ASSERT(check);
  62. check = connect(client, SIGNAL(presenceReceived(QXmppPresence)),
  63. this, SLOT(_q_presenceReceived(QXmppPresence)));
  64. Q_ASSERT(check);
  65. }
  66. QXmppRosterManager::~QXmppRosterManager()
  67. {
  68. delete d;
  69. }
  70. /// Accepts a subscription request.
  71. ///
  72. /// You can call this method in reply to the subscriptionRequest() signal.
  73. bool QXmppRosterManager::acceptSubscription(const QString &bareJid, const QString &reason)
  74. {
  75. QXmppPresence presence;
  76. presence.setTo(bareJid);
  77. presence.setType(QXmppPresence::Subscribed);
  78. presence.setStatusText(reason);
  79. return client()->sendPacket(presence);
  80. }
  81. /// Upon XMPP connection, request the roster.
  82. ///
  83. void QXmppRosterManager::_q_connected()
  84. {
  85. QXmppRosterIq roster;
  86. roster.setType(QXmppIq::Get);
  87. roster.setFrom(client()->configuration().jid());
  88. d->rosterReqId = roster.id();
  89. if (client()->isAuthenticated())
  90. client()->sendPacket(roster);
  91. }
  92. void QXmppRosterManager::_q_disconnected()
  93. {
  94. d->entries.clear();
  95. d->presences.clear();
  96. d->isRosterReceived = false;
  97. }
  98. /// \cond
  99. bool QXmppRosterManager::handleStanza(const QDomElement &element)
  100. {
  101. if (element.tagName() != "iq" || !QXmppRosterIq::isRosterIq(element))
  102. return false;
  103. // Security check: only server should send this iq
  104. // from() should be either empty or bareJid of the user
  105. const QString fromJid = element.attribute("from");
  106. if (!fromJid.isEmpty() && QXmppUtils::jidToBareJid(fromJid) != client()->configuration().jidBare())
  107. return false;
  108. QXmppRosterIq rosterIq;
  109. rosterIq.parse(element);
  110. bool isInitial = (d->rosterReqId == rosterIq.id());
  111. switch(rosterIq.type())
  112. {
  113. case QXmppIq::Set:
  114. {
  115. // send result iq
  116. QXmppIq returnIq(QXmppIq::Result);
  117. returnIq.setId(rosterIq.id());
  118. client()->sendPacket(returnIq);
  119. // store updated entries and notify changes
  120. const QList<QXmppRosterIq::Item> items = rosterIq.items();
  121. foreach (const QXmppRosterIq::Item &item, items) {
  122. const QString bareJid = item.bareJid();
  123. if (item.subscriptionType() == QXmppRosterIq::Item::Remove) {
  124. if (d->entries.remove(bareJid)) {
  125. // notify the user that the item was removed
  126. emit itemRemoved(bareJid);
  127. }
  128. } else {
  129. const bool added = !d->entries.contains(bareJid);
  130. d->entries.insert(bareJid, item);
  131. if (added) {
  132. // notify the user that the item was added
  133. emit itemAdded(bareJid);
  134. } else {
  135. // notify the user that the item changed
  136. emit itemChanged(bareJid);
  137. }
  138. }
  139. }
  140. }
  141. break;
  142. case QXmppIq::Result:
  143. {
  144. const QList<QXmppRosterIq::Item> items = rosterIq.items();
  145. foreach (const QXmppRosterIq::Item &item, items) {
  146. const QString bareJid = item.bareJid();
  147. d->entries.insert(bareJid, item);
  148. }
  149. if (isInitial)
  150. {
  151. d->isRosterReceived = true;
  152. emit rosterReceived();
  153. }
  154. break;
  155. }
  156. default:
  157. break;
  158. }
  159. return true;
  160. }
  161. /// \endcond
  162. void QXmppRosterManager::_q_presenceReceived(const QXmppPresence& presence)
  163. {
  164. const QString jid = presence.from();
  165. const QString bareJid = QXmppUtils::jidToBareJid(jid);
  166. const QString resource = QXmppUtils::jidToResource(jid);
  167. if (bareJid.isEmpty())
  168. return;
  169. switch(presence.type())
  170. {
  171. case QXmppPresence::Available:
  172. d->presences[bareJid][resource] = presence;
  173. emit presenceChanged(bareJid, resource);
  174. break;
  175. case QXmppPresence::Unavailable:
  176. d->presences[bareJid].remove(resource);
  177. emit presenceChanged(bareJid, resource);
  178. break;
  179. case QXmppPresence::Subscribe:
  180. if (client()->configuration().autoAcceptSubscriptions())
  181. {
  182. // accept subscription request
  183. acceptSubscription(bareJid);
  184. // ask for reciprocal subscription
  185. subscribe(bareJid);
  186. } else {
  187. emit subscriptionReceived(bareJid);
  188. }
  189. break;
  190. default:
  191. break;
  192. }
  193. }
  194. /// Refuses a subscription request.
  195. ///
  196. /// You can call this method in reply to the subscriptionRequest() signal.
  197. bool QXmppRosterManager::refuseSubscription(const QString &bareJid, const QString &reason)
  198. {
  199. QXmppPresence presence;
  200. presence.setTo(bareJid);
  201. presence.setType(QXmppPresence::Unsubscribed);
  202. presence.setStatusText(reason);
  203. return client()->sendPacket(presence);
  204. }
  205. /// Adds a new item to the roster without sending any subscription requests.
  206. ///
  207. /// As a result, the server will initiate a roster push, causing the
  208. /// itemAdded() or itemChanged() signal to be emitted.
  209. ///
  210. /// \param bareJid
  211. /// \param name Optional name for the item.
  212. /// \param groups Optional groups for the item.
  213. bool QXmppRosterManager::addItem(const QString &bareJid, const QString &name, const QSet<QString> &groups)
  214. {
  215. QXmppRosterIq::Item item;
  216. item.setBareJid(bareJid);
  217. item.setName(name);
  218. item.setGroups(groups);
  219. item.setSubscriptionType(QXmppRosterIq::Item::NotSet);
  220. QXmppRosterIq iq;
  221. iq.setType(QXmppIq::Set);
  222. iq.addItem(item);
  223. return client()->sendPacket(iq);
  224. }
  225. /// Removes a roster item and cancels subscriptions to and from the contact.
  226. ///
  227. /// As a result, the server will initiate a roster push, causing the
  228. /// itemRemoved() signal to be emitted.
  229. ///
  230. /// \param bareJid
  231. bool QXmppRosterManager::removeItem(const QString &bareJid)
  232. {
  233. QXmppRosterIq::Item item;
  234. item.setBareJid(bareJid);
  235. item.setSubscriptionType(QXmppRosterIq::Item::Remove);
  236. QXmppRosterIq iq;
  237. iq.setType(QXmppIq::Set);
  238. iq.addItem(item);
  239. return client()->sendPacket(iq);
  240. }
  241. /// Renames a roster item.
  242. ///
  243. /// As a result, the server will initiate a roster push, causing the
  244. /// itemChanged() signal to be emitted.
  245. ///
  246. /// \param bareJid
  247. /// \param name
  248. bool QXmppRosterManager::renameItem(const QString &bareJid, const QString &name)
  249. {
  250. if (!d->entries.contains(bareJid))
  251. return false;
  252. QXmppRosterIq::Item item = d->entries.value(bareJid);
  253. item.setName(name);
  254. QXmppRosterIq iq;
  255. iq.setType(QXmppIq::Set);
  256. iq.addItem(item);
  257. return client()->sendPacket(iq);
  258. }
  259. /// Requests a subscription to the given contact.
  260. ///
  261. /// As a result, the server will initiate a roster push, causing the
  262. /// itemAdded() or itemChanged() signal to be emitted.
  263. bool QXmppRosterManager::subscribe(const QString &bareJid, const QString &reason)
  264. {
  265. QXmppPresence packet;
  266. packet.setTo(QXmppUtils::jidToBareJid(bareJid));
  267. packet.setType(QXmppPresence::Subscribe);
  268. packet.setStatusText(reason);
  269. return client()->sendPacket(packet);
  270. }
  271. /// Removes a subscription to the given contact.
  272. ///
  273. /// As a result, the server will initiate a roster push, causing the
  274. /// itemChanged() signal to be emitted.
  275. bool QXmppRosterManager::unsubscribe(const QString &bareJid, const QString &reason)
  276. {
  277. QXmppPresence packet;
  278. packet.setTo(QXmppUtils::jidToBareJid(bareJid));
  279. packet.setType(QXmppPresence::Unsubscribe);
  280. packet.setStatusText(reason);
  281. return client()->sendPacket(packet);
  282. }
  283. /// Function to get all the bareJids present in the roster.
  284. ///
  285. /// \return QStringList list of all the bareJids
  286. ///
  287. QStringList QXmppRosterManager::getRosterBareJids() const
  288. {
  289. return d->entries.keys();
  290. }
  291. /// Returns the roster entry of the given bareJid. If the bareJid is not in the
  292. /// database and empty QXmppRosterIq::Item will be returned.
  293. ///
  294. /// \param bareJid as a QString
  295. ///
  296. QXmppRosterIq::Item QXmppRosterManager::getRosterEntry(
  297. const QString& bareJid) const
  298. {
  299. // will return blank entry if bareJid does'nt exist
  300. if(d->entries.contains(bareJid))
  301. return d->entries.value(bareJid);
  302. else
  303. return QXmppRosterIq::Item();
  304. }
  305. /// Get all the associated resources with the given bareJid.
  306. ///
  307. /// \param bareJid as a QString
  308. /// \return list of associated resources as a QStringList
  309. ///
  310. QStringList QXmppRosterManager::getResources(const QString& bareJid) const
  311. {
  312. if(d->presences.contains(bareJid))
  313. return d->presences[bareJid].keys();
  314. else
  315. return QStringList();
  316. }
  317. /// Get all the presences of all the resources of the given bareJid. A bareJid
  318. /// can have multiple resources and each resource will have a presence
  319. /// associated with it.
  320. ///
  321. /// \param bareJid as a QString
  322. /// \return Map of resource and its respective presence QMap<QString, QXmppPresence>
  323. ///
  324. QMap<QString, QXmppPresence> QXmppRosterManager::getAllPresencesForBareJid(
  325. const QString& bareJid) const
  326. {
  327. if(d->presences.contains(bareJid))
  328. return d->presences[bareJid];
  329. else
  330. return QMap<QString, QXmppPresence>();
  331. }
  332. /// Get the presence of the given resource of the given bareJid.
  333. ///
  334. /// \param bareJid as a QString
  335. /// \param resource as a QString
  336. /// \return QXmppPresence
  337. ///
  338. QXmppPresence QXmppRosterManager::getPresence(const QString& bareJid,
  339. const QString& resource) const
  340. {
  341. if(d->presences.contains(bareJid) && d->presences[bareJid].contains(resource))
  342. return d->presences[bareJid][resource];
  343. else
  344. {
  345. QXmppPresence presence;
  346. presence.setType(QXmppPresence::Unavailable);
  347. return presence;
  348. }
  349. }
  350. /// Function to check whether the roster has been received or not.
  351. ///
  352. /// \return true if roster received else false
  353. bool QXmppRosterManager::isRosterReceived() const
  354. {
  355. return d->isRosterReceived;
  356. }