QXmppDiscoveryIq.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. * Copyright (C) 2008-2012 The QXmpp developers
  3. *
  4. * Author:
  5. * Jeremy Lainé
  6. *
  7. * Source:
  8. * http://code.google.com/p/qxmpp
  9. *
  10. * This file is a part of QXmpp library.
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation; either
  15. * version 2.1 of the License, or (at your option) any later version.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. */
  23. #include <QCryptographicHash>
  24. #include <QDomElement>
  25. #include "QXmppConstants.h"
  26. #include "QXmppDiscoveryIq.h"
  27. #include "QXmppUtils.h"
  28. static bool identityLessThan(const QXmppDiscoveryIq::Identity &i1, const QXmppDiscoveryIq::Identity &i2)
  29. {
  30. if (i1.category() < i2.category())
  31. return true;
  32. else if (i1.category() > i2.category())
  33. return false;
  34. if (i1.type() < i2.type())
  35. return true;
  36. else if (i1.type() > i2.type())
  37. return false;
  38. if (i1.language() < i2.language())
  39. return true;
  40. else if (i1.language() > i2.language())
  41. return false;
  42. if (i1.name() < i2.name())
  43. return true;
  44. else if (i1.name() > i2.name())
  45. return false;
  46. return false;
  47. }
  48. QString QXmppDiscoveryIq::Identity::category() const
  49. {
  50. return m_category;
  51. }
  52. void QXmppDiscoveryIq::Identity::setCategory(const QString &category)
  53. {
  54. m_category = category;
  55. }
  56. QString QXmppDiscoveryIq::Identity::language() const
  57. {
  58. return m_language;
  59. }
  60. void QXmppDiscoveryIq::Identity::setLanguage(const QString &language)
  61. {
  62. m_language = language;
  63. }
  64. QString QXmppDiscoveryIq::Identity::name() const
  65. {
  66. return m_name;
  67. }
  68. void QXmppDiscoveryIq::Identity::setName(const QString &name)
  69. {
  70. m_name = name;
  71. }
  72. QString QXmppDiscoveryIq::Identity::type() const
  73. {
  74. return m_type;
  75. }
  76. void QXmppDiscoveryIq::Identity::setType(const QString &type)
  77. {
  78. m_type = type;
  79. }
  80. QString QXmppDiscoveryIq::Item::jid() const
  81. {
  82. return m_jid;
  83. }
  84. void QXmppDiscoveryIq::Item::setJid(const QString &jid)
  85. {
  86. m_jid = jid;
  87. }
  88. QString QXmppDiscoveryIq::Item::name() const
  89. {
  90. return m_name;
  91. }
  92. void QXmppDiscoveryIq::Item::setName(const QString &name)
  93. {
  94. m_name = name;
  95. }
  96. QString QXmppDiscoveryIq::Item::node() const
  97. {
  98. return m_node;
  99. }
  100. void QXmppDiscoveryIq::Item::setNode(const QString &node)
  101. {
  102. m_node = node;
  103. }
  104. QStringList QXmppDiscoveryIq::features() const
  105. {
  106. return m_features;
  107. }
  108. void QXmppDiscoveryIq::setFeatures(const QStringList &features)
  109. {
  110. m_features = features;
  111. }
  112. QList<QXmppDiscoveryIq::Identity> QXmppDiscoveryIq::identities() const
  113. {
  114. return m_identities;
  115. }
  116. void QXmppDiscoveryIq::setIdentities(const QList<QXmppDiscoveryIq::Identity> &identities)
  117. {
  118. m_identities = identities;
  119. }
  120. QList<QXmppDiscoveryIq::Item> QXmppDiscoveryIq::items() const
  121. {
  122. return m_items;
  123. }
  124. void QXmppDiscoveryIq::setItems(const QList<QXmppDiscoveryIq::Item> &items)
  125. {
  126. m_items = items;
  127. }
  128. /// Returns the QXmppDataForm for this IQ, as defined by
  129. /// XEP-0128: Service Discovery Extensions.
  130. ///
  131. QXmppDataForm QXmppDiscoveryIq::form() const
  132. {
  133. return m_form;
  134. }
  135. /// Sets the QXmppDataForm for this IQ, as define by
  136. /// XEP-0128: Service Discovery Extensions.
  137. ///
  138. /// \param form
  139. ///
  140. void QXmppDiscoveryIq::setForm(const QXmppDataForm &form)
  141. {
  142. m_form = form;
  143. }
  144. QString QXmppDiscoveryIq::queryNode() const
  145. {
  146. return m_queryNode;
  147. }
  148. void QXmppDiscoveryIq::setQueryNode(const QString &node)
  149. {
  150. m_queryNode = node;
  151. }
  152. enum QXmppDiscoveryIq::QueryType QXmppDiscoveryIq::queryType() const
  153. {
  154. return m_queryType;
  155. }
  156. void QXmppDiscoveryIq::setQueryType(enum QXmppDiscoveryIq::QueryType type)
  157. {
  158. m_queryType = type;
  159. }
  160. /// Calculate the verification string for XEP-0115 : Entity Capabilities
  161. QByteArray QXmppDiscoveryIq::verificationString() const
  162. {
  163. QString S;
  164. QList<QXmppDiscoveryIq::Identity> sortedIdentities = m_identities;
  165. qSort(sortedIdentities.begin(), sortedIdentities.end(), identityLessThan);
  166. QStringList sortedFeatures = m_features;
  167. qSort(sortedFeatures);
  168. sortedFeatures.removeDuplicates();
  169. foreach (const QXmppDiscoveryIq::Identity &identity, sortedIdentities)
  170. S += QString("%1/%2/%3/%4<").arg(identity.category(), identity.type(), identity.language(), identity.name());
  171. foreach (const QString &feature, sortedFeatures)
  172. S += feature + QLatin1String("<");
  173. if (!m_form.isNull()) {
  174. QMap<QString, QXmppDataForm::Field> fieldMap;
  175. foreach (const QXmppDataForm::Field &field, m_form.fields()) {
  176. fieldMap.insert(field.key(), field);
  177. }
  178. if (fieldMap.contains("FORM_TYPE")) {
  179. const QXmppDataForm::Field field = fieldMap.take("FORM_TYPE");
  180. S += field.value().toString() + QLatin1String("<");
  181. QStringList keys = fieldMap.keys();
  182. qSort(keys);
  183. foreach (const QString &key, keys) {
  184. const QXmppDataForm::Field field = fieldMap.value(key);
  185. S += key + QLatin1String("<");
  186. if (field.value().canConvert<QStringList>()) {
  187. QStringList list = field.value().toStringList();
  188. list.sort();
  189. S += list.join(QLatin1String("<"));
  190. } else {
  191. S += field.value().toString();
  192. }
  193. S += QLatin1String("<");
  194. }
  195. } else {
  196. qWarning("QXmppDiscoveryIq form does not contain FORM_TYPE");
  197. }
  198. }
  199. QCryptographicHash hasher(QCryptographicHash::Sha1);
  200. hasher.addData(S.toUtf8());
  201. return hasher.result();
  202. }
  203. /// \cond
  204. bool QXmppDiscoveryIq::isDiscoveryIq(const QDomElement &element)
  205. {
  206. QDomElement queryElement = element.firstChildElement("query");
  207. return (queryElement.namespaceURI() == ns_disco_info ||
  208. queryElement.namespaceURI() == ns_disco_items);
  209. }
  210. void QXmppDiscoveryIq::parseElementFromChild(const QDomElement &element)
  211. {
  212. QDomElement queryElement = element.firstChildElement("query");
  213. m_queryNode = queryElement.attribute("node");
  214. if (queryElement.namespaceURI() == ns_disco_items)
  215. m_queryType = ItemsQuery;
  216. else
  217. m_queryType = InfoQuery;
  218. QDomElement itemElement = queryElement.firstChildElement();
  219. while (!itemElement.isNull())
  220. {
  221. if (itemElement.tagName() == "feature")
  222. {
  223. m_features.append(itemElement.attribute("var"));
  224. }
  225. else if (itemElement.tagName() == "identity")
  226. {
  227. QXmppDiscoveryIq::Identity identity;
  228. identity.setLanguage(itemElement.attribute("xml:lang"));
  229. identity.setCategory(itemElement.attribute("category"));
  230. identity.setName(itemElement.attribute("name"));
  231. identity.setType(itemElement.attribute("type"));
  232. // FIXME: for some reason the language does not found,
  233. // so we are forced to use QDomNamedNodeMap
  234. QDomNamedNodeMap m(itemElement.attributes());
  235. for (int i = 0; i < m.size(); ++i) {
  236. if (m.item(i).nodeName() == "xml:lang") {
  237. identity.setLanguage(m.item(i).nodeValue());
  238. break;
  239. }
  240. }
  241. m_identities.append(identity);
  242. }
  243. else if (itemElement.tagName() == "item")
  244. {
  245. QXmppDiscoveryIq::Item item;
  246. item.setJid(itemElement.attribute("jid"));
  247. item.setName(itemElement.attribute("name"));
  248. item.setNode(itemElement.attribute("node"));
  249. m_items.append(item);
  250. }
  251. else if (itemElement.tagName() == "x" &&
  252. itemElement.namespaceURI() == ns_data)
  253. {
  254. m_form.parse(itemElement);
  255. }
  256. itemElement = itemElement.nextSiblingElement();
  257. }
  258. }
  259. void QXmppDiscoveryIq::toXmlElementFromChild(QXmlStreamWriter *writer) const
  260. {
  261. writer->writeStartElement("query");
  262. writer->writeAttribute("xmlns",
  263. m_queryType == InfoQuery ? ns_disco_info : ns_disco_items);
  264. helperToXmlAddAttribute(writer, "node", m_queryNode);
  265. if (m_queryType == InfoQuery) {
  266. foreach (const QXmppDiscoveryIq::Identity& identity, m_identities) {
  267. writer->writeStartElement("identity");
  268. helperToXmlAddAttribute(writer, "xml:lang", identity.language());
  269. helperToXmlAddAttribute(writer, "category", identity.category());
  270. helperToXmlAddAttribute(writer, "name", identity.name());
  271. helperToXmlAddAttribute(writer, "type", identity.type());
  272. writer->writeEndElement();
  273. }
  274. foreach (const QString &feature, m_features) {
  275. writer->writeStartElement("feature");
  276. helperToXmlAddAttribute(writer, "var", feature);
  277. writer->writeEndElement();
  278. }
  279. } else {
  280. foreach (const QXmppDiscoveryIq::Item& item, m_items) {
  281. writer->writeStartElement("item");
  282. helperToXmlAddAttribute(writer, "jid", item.jid());
  283. helperToXmlAddAttribute(writer, "name", item.name());
  284. helperToXmlAddAttribute(writer, "node", item.node());
  285. writer->writeEndElement();
  286. }
  287. }
  288. m_form.toXml(writer);
  289. writer->writeEndElement();
  290. }
  291. /// \endcond