QXmppMessage.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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 <QTextStream>
  26. #include <QXmlStreamWriter>
  27. #include "QXmppConstants.h"
  28. #include "QXmppMessage.h"
  29. #include "QXmppUtils.h"
  30. static const char* chat_states[] = {
  31. "",
  32. "active",
  33. "inactive",
  34. "gone",
  35. "composing",
  36. "paused",
  37. };
  38. static const char* message_types[] = {
  39. "error",
  40. "normal",
  41. "chat",
  42. "groupchat",
  43. "headline"
  44. };
  45. static const char *ns_xhtml = "http://www.w3.org/1999/xhtml";
  46. enum StampType
  47. {
  48. LegacyDelayedDelivery, // XEP-0091: Legacy Delayed Delivery
  49. DelayedDelivery, // XEP-0203: Delayed Delivery
  50. };
  51. class QXmppMessagePrivate : public QSharedData
  52. {
  53. public:
  54. QXmppMessage::Type type;
  55. QDateTime stamp;
  56. StampType stampType;
  57. QXmppMessage::State state;
  58. bool attentionRequested;
  59. QString body;
  60. QString subject;
  61. QString thread;
  62. // XEP-0071: XHTML-IM
  63. QString xhtml;
  64. // Request message receipt as per XEP-0184.
  65. QString receiptId;
  66. bool receiptRequested;
  67. // XEP-0249: Direct MUC Invitations
  68. QString mucInvitationJid;
  69. QString mucInvitationPassword;
  70. QString mucInvitationReason;
  71. };
  72. /// Constructs a QXmppMessage.
  73. ///
  74. /// \param from
  75. /// \param to
  76. /// \param body
  77. /// \param thread
  78. QXmppMessage::QXmppMessage(const QString& from, const QString& to, const
  79. QString& body, const QString& thread)
  80. : QXmppStanza(from, to)
  81. , d(new QXmppMessagePrivate)
  82. {
  83. d->type = Chat;
  84. d->stampType = DelayedDelivery;
  85. d->state = None;
  86. d->attentionRequested = false;
  87. d->body = body;
  88. d->thread = thread;
  89. d->receiptRequested = false;
  90. }
  91. /// Constructs a copy of \a other.
  92. QXmppMessage::QXmppMessage(const QXmppMessage &other)
  93. : QXmppStanza(other)
  94. , d(other.d)
  95. {
  96. }
  97. QXmppMessage::~QXmppMessage()
  98. {
  99. }
  100. /// Assigns \a other to this message.
  101. QXmppMessage& QXmppMessage::operator=(const QXmppMessage &other)
  102. {
  103. QXmppStanza::operator=(other);
  104. d = other.d;
  105. return *this;
  106. }
  107. /// Returns the message's body.
  108. ///
  109. QString QXmppMessage::body() const
  110. {
  111. return d->body;
  112. }
  113. /// Sets the message's body.
  114. ///
  115. /// \param body
  116. void QXmppMessage::setBody(const QString& body)
  117. {
  118. d->body = body;
  119. }
  120. /// Returns true if the user's attention is requested, as defined
  121. /// by XEP-0224: Attention.
  122. bool QXmppMessage::isAttentionRequested() const
  123. {
  124. return d->attentionRequested;
  125. }
  126. /// Sets whether the user's attention is requested, as defined
  127. /// by XEP-0224: Attention.
  128. ///
  129. /// \a param requested
  130. void QXmppMessage::setAttentionRequested(bool requested)
  131. {
  132. d->attentionRequested = requested;
  133. }
  134. /// Returns true if a delivery receipt is requested, as defined
  135. /// by XEP-0184: Message Delivery Receipts.
  136. bool QXmppMessage::isReceiptRequested() const
  137. {
  138. return d->receiptRequested;
  139. }
  140. /// Sets whether a delivery receipt is requested, as defined
  141. /// by XEP-0184: Message Delivery Receipts.
  142. ///
  143. /// \a param requested
  144. void QXmppMessage::setReceiptRequested(bool requested)
  145. {
  146. d->receiptRequested = requested;
  147. if (requested && id().isEmpty())
  148. generateAndSetNextId();
  149. }
  150. /// If this message is a delivery receipt, returns the ID of the
  151. /// original message.
  152. QString QXmppMessage::receiptId() const
  153. {
  154. return d->receiptId;
  155. }
  156. /// Make this message a delivery receipt for the message with
  157. /// the given \a id.
  158. void QXmppMessage::setReceiptId(const QString &id)
  159. {
  160. d->receiptId = id;
  161. }
  162. /// Returns the JID for a multi-user chat direct invitation as defined
  163. /// by XEP-0249: Direct MUC Invitations.
  164. QString QXmppMessage::mucInvitationJid() const
  165. {
  166. return d->mucInvitationJid;
  167. }
  168. /// Sets the JID for a multi-user chat direct invitation as defined
  169. /// by XEP-0249: Direct MUC Invitations.
  170. void QXmppMessage::setMucInvitationJid(const QString &jid)
  171. {
  172. d->mucInvitationJid = jid;
  173. }
  174. /// Returns the password for a multi-user chat direct invitation as defined
  175. /// by XEP-0249: Direct MUC Invitations.
  176. QString QXmppMessage::mucInvitationPassword() const
  177. {
  178. return d->mucInvitationPassword;
  179. }
  180. /// Sets the \a password for a multi-user chat direct invitation as defined
  181. /// by XEP-0249: Direct MUC Invitations.
  182. void QXmppMessage::setMucInvitationPassword(const QString &password)
  183. {
  184. d->mucInvitationPassword = password;
  185. }
  186. /// Returns the reason for a multi-user chat direct invitation as defined
  187. /// by XEP-0249: Direct MUC Invitations.
  188. QString QXmppMessage::mucInvitationReason() const
  189. {
  190. return d->mucInvitationReason;
  191. }
  192. /// Sets the \a reason for a multi-user chat direct invitation as defined
  193. /// by XEP-0249: Direct MUC Invitations.
  194. void QXmppMessage::setMucInvitationReason(const QString &reason)
  195. {
  196. d->mucInvitationReason = reason;
  197. }
  198. /// Returns the message's type.
  199. ///
  200. QXmppMessage::Type QXmppMessage::type() const
  201. {
  202. return d->type;
  203. }
  204. /// Sets the message's type.
  205. ///
  206. /// \param type
  207. void QXmppMessage::setType(QXmppMessage::Type type)
  208. {
  209. d->type = type;
  210. }
  211. /// Returns the message's timestamp (if any).
  212. QDateTime QXmppMessage::stamp() const
  213. {
  214. return d->stamp;
  215. }
  216. /// Sets the message's timestamp.
  217. ///
  218. /// \param stamp
  219. void QXmppMessage::setStamp(const QDateTime &stamp)
  220. {
  221. d->stamp = stamp;
  222. }
  223. /// Returns the message's chat state.
  224. ///
  225. QXmppMessage::State QXmppMessage::state() const
  226. {
  227. return d->state;
  228. }
  229. /// Sets the message's chat state.
  230. ///
  231. /// \param state
  232. void QXmppMessage::setState(QXmppMessage::State state)
  233. {
  234. d->state = state;
  235. }
  236. /// Returns the message's subject.
  237. ///
  238. QString QXmppMessage::subject() const
  239. {
  240. return d->subject;
  241. }
  242. /// Sets the message's subject.
  243. ///
  244. /// \param subject
  245. void QXmppMessage::setSubject(const QString& subject)
  246. {
  247. d->subject = subject;
  248. }
  249. /// Returns the message's thread.
  250. QString QXmppMessage::thread() const
  251. {
  252. return d->thread;
  253. }
  254. /// Sets the message's thread.
  255. ///
  256. /// \param thread
  257. void QXmppMessage::setThread(const QString& thread)
  258. {
  259. d->thread = thread;
  260. }
  261. /// Returns the message's XHTML body as defined by
  262. /// XEP-0071: XHTML-IM.
  263. QString QXmppMessage::xhtml() const
  264. {
  265. return d->xhtml;
  266. }
  267. /// Sets the message's XHTML body as defined by
  268. /// XEP-0071: XHTML-IM.
  269. void QXmppMessage::setXhtml(const QString &xhtml)
  270. {
  271. d->xhtml = xhtml;
  272. }
  273. /// \cond
  274. void QXmppMessage::parse(const QDomElement &element)
  275. {
  276. QXmppStanza::parse(element);
  277. const QString type = element.attribute("type");
  278. d->type = Normal;
  279. for (int i = Error; i <= Headline; i++) {
  280. if (type == message_types[i]) {
  281. d->type = static_cast<Type>(i);
  282. break;
  283. }
  284. }
  285. d->body = element.firstChildElement("body").text();
  286. d->subject = element.firstChildElement("subject").text();
  287. d->thread = element.firstChildElement("thread").text();
  288. // chat states
  289. for (int i = Active; i <= Paused; i++)
  290. {
  291. QDomElement stateElement = element.firstChildElement(chat_states[i]);
  292. if (!stateElement.isNull() &&
  293. stateElement.namespaceURI() == ns_chat_states)
  294. {
  295. d->state = static_cast<QXmppMessage::State>(i);
  296. break;
  297. }
  298. }
  299. // XEP-0071: XHTML-IM
  300. QDomElement htmlElement = element.firstChildElement("html");
  301. if (!htmlElement.isNull() && htmlElement.namespaceURI() == ns_xhtml_im) {
  302. QDomElement bodyElement = htmlElement.firstChildElement("body");
  303. if (!bodyElement.isNull() && bodyElement.namespaceURI() == ns_xhtml) {
  304. QTextStream stream(&d->xhtml, QIODevice::WriteOnly);
  305. bodyElement.save(stream, 0);
  306. d->xhtml = d->xhtml.mid(d->xhtml.indexOf('>') + 1);
  307. d->xhtml.replace(" xmlns=\"http://www.w3.org/1999/xhtml\"", "");
  308. d->xhtml.replace("</body>", "");
  309. d->xhtml = d->xhtml.trimmed();
  310. }
  311. }
  312. // XEP-0184: Message Delivery Receipts
  313. QDomElement receivedElement = element.firstChildElement("received");
  314. if (!receivedElement.isNull() && receivedElement.namespaceURI() == ns_message_receipts) {
  315. d->receiptId = receivedElement.attribute("id");
  316. // compatibility with old-style XEP
  317. if (d->receiptId.isEmpty())
  318. d->receiptId = id();
  319. } else {
  320. d->receiptId = QString();
  321. }
  322. d->receiptRequested = element.firstChildElement("request").namespaceURI() == ns_message_receipts;
  323. // XEP-0203: Delayed Delivery
  324. QDomElement delayElement = element.firstChildElement("delay");
  325. if (!delayElement.isNull() && delayElement.namespaceURI() == ns_delayed_delivery)
  326. {
  327. const QString str = delayElement.attribute("stamp");
  328. d->stamp = QXmppUtils::datetimeFromString(str);
  329. d->stampType = DelayedDelivery;
  330. }
  331. // XEP-0224: Attention
  332. d->attentionRequested = element.firstChildElement("attention").namespaceURI() == ns_attention;
  333. QXmppElementList extensions;
  334. QDomElement xElement = element.firstChildElement("x");
  335. while (!xElement.isNull())
  336. {
  337. if (xElement.namespaceURI() == ns_legacy_delayed_delivery)
  338. {
  339. // XEP-0091: Legacy Delayed Delivery
  340. const QString str = xElement.attribute("stamp");
  341. d->stamp = QDateTime::fromString(str, "yyyyMMddThh:mm:ss");
  342. d->stamp.setTimeSpec(Qt::UTC);
  343. d->stampType = LegacyDelayedDelivery;
  344. } else if (xElement.namespaceURI() == ns_conference) {
  345. // XEP-0249: Direct MUC Invitations
  346. d->mucInvitationJid = xElement.attribute("jid");
  347. d->mucInvitationPassword = xElement.attribute("password");
  348. d->mucInvitationReason = xElement.attribute("reason");
  349. } else {
  350. // other extensions
  351. extensions << QXmppElement(xElement);
  352. }
  353. xElement = xElement.nextSiblingElement("x");
  354. }
  355. setExtensions(extensions);
  356. }
  357. void QXmppMessage::toXml(QXmlStreamWriter *xmlWriter) const
  358. {
  359. xmlWriter->writeStartElement("message");
  360. helperToXmlAddAttribute(xmlWriter, "xml:lang", lang());
  361. helperToXmlAddAttribute(xmlWriter, "id", id());
  362. helperToXmlAddAttribute(xmlWriter, "to", to());
  363. helperToXmlAddAttribute(xmlWriter, "from", from());
  364. helperToXmlAddAttribute(xmlWriter, "type", message_types[d->type]);
  365. if (!d->subject.isEmpty())
  366. helperToXmlAddTextElement(xmlWriter, "subject", d->subject);
  367. if (!d->body.isEmpty())
  368. helperToXmlAddTextElement(xmlWriter, "body", d->body);
  369. if (!d->thread.isEmpty())
  370. helperToXmlAddTextElement(xmlWriter, "thread", d->thread);
  371. error().toXml(xmlWriter);
  372. //Anatoly - MeegIM
  373. helperToXmlAddAttribute( xmlWriter, "id", d->receiptId );
  374. // chat states
  375. if (d->state > None && d->state <= Paused)
  376. {
  377. xmlWriter->writeStartElement(chat_states[d->state]);
  378. xmlWriter->writeAttribute("xmlns", ns_chat_states);
  379. xmlWriter->writeEndElement();
  380. }
  381. // XEP-0071: XHTML-IM
  382. if (!d->xhtml.isEmpty()) {
  383. xmlWriter->writeStartElement("html");
  384. xmlWriter->writeAttribute("xmlns", ns_xhtml_im);
  385. xmlWriter->writeStartElement("body");
  386. xmlWriter->writeAttribute("xmlns", ns_xhtml);
  387. xmlWriter->writeCharacters("");
  388. xmlWriter->device()->write(d->xhtml.toUtf8());
  389. xmlWriter->writeEndElement();
  390. xmlWriter->writeEndElement();
  391. }
  392. // time stamp
  393. if (d->stamp.isValid())
  394. {
  395. QDateTime utcStamp = d->stamp.toUTC();
  396. if (d->stampType == DelayedDelivery)
  397. {
  398. // XEP-0203: Delayed Delivery
  399. xmlWriter->writeStartElement("delay");
  400. xmlWriter->writeAttribute("xmlns", ns_delayed_delivery);
  401. helperToXmlAddAttribute(xmlWriter, "stamp", QXmppUtils::datetimeToString(utcStamp));
  402. xmlWriter->writeEndElement();
  403. } else {
  404. // XEP-0091: Legacy Delayed Delivery
  405. xmlWriter->writeStartElement("x");
  406. xmlWriter->writeAttribute("xmlns", ns_legacy_delayed_delivery);
  407. helperToXmlAddAttribute(xmlWriter, "stamp", utcStamp.toString("yyyyMMddThh:mm:ss"));
  408. xmlWriter->writeEndElement();
  409. }
  410. }
  411. // XEP-0184: Message Delivery Receipts
  412. if (!d->receiptId.isEmpty()) {
  413. xmlWriter->writeStartElement("received");
  414. xmlWriter->writeAttribute("xmlns", ns_message_receipts);
  415. xmlWriter->writeAttribute("id", d->receiptId);
  416. xmlWriter->writeEndElement();
  417. }
  418. if (d->receiptRequested) {
  419. xmlWriter->writeStartElement("request");
  420. xmlWriter->writeAttribute("xmlns", ns_message_receipts);
  421. xmlWriter->writeEndElement();
  422. }
  423. // XEP-0224: Attention
  424. if (d->attentionRequested) {
  425. xmlWriter->writeStartElement("attention");
  426. xmlWriter->writeAttribute("xmlns", ns_attention);
  427. xmlWriter->writeEndElement();
  428. }
  429. // XEP-0249: Direct MUC Invitations
  430. if (!d->mucInvitationJid.isEmpty()) {
  431. xmlWriter->writeStartElement("x");
  432. xmlWriter->writeAttribute("xmlns", ns_conference);
  433. xmlWriter->writeAttribute("jid", d->mucInvitationJid);
  434. if (!d->mucInvitationPassword.isEmpty())
  435. xmlWriter->writeAttribute("password", d->mucInvitationPassword);
  436. if (!d->mucInvitationReason.isEmpty())
  437. xmlWriter->writeAttribute("reason", d->mucInvitationReason);
  438. xmlWriter->writeEndElement();
  439. }
  440. // other extensions
  441. QXmppStanza::extensionsToXml(xmlWriter);
  442. xmlWriter->writeEndElement();
  443. }
  444. /// \endcond