Advertisement
Guest User

Untitled

a guest
Apr 10th, 2015
198
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.41 KB | None | 0 0
  1. --- a/libpurple/protocols/jabber/Makefile.am
  2. +++ b/libpurple/protocols/jabber/Makefile.am
  3. @@ -65,6 +65,8 @@
  4. jingle/transport.h \
  5. jutil.c \
  6. jutil.h \
  7. + mam.c \
  8. + mam.h \
  9. message.c \
  10. message.h \
  11. namespaces.h \
  12. --- a/libpurple/protocols/jabber/Makefile.mingw
  13. +++ b/libpurple/protocols/jabber/Makefile.mingw
  14. @@ -74,6 +74,7 @@
  15. jingle/session.c \
  16. jingle/transport.c \
  17. jutil.c \
  18. + mam.c \
  19. message.c \
  20. oob.c \
  21. parser.c \
  22. --- a/libpurple/protocols/jabber/disco.c
  23. +++ b/libpurple/protocols/jabber/disco.c
  24. @@ -36,6 +36,7 @@
  25. #include "iq.h"
  26. #include "jabber.h"
  27. #include "jingle/jingle.h"
  28. +#include "mam.h"
  29. #include "pep.h"
  30. #include "presence.h"
  31. #include "roster.h"
  32. @@ -295,13 +296,16 @@
  33. capabilities |= JABBER_CAP_PING;
  34. else if(!strcmp(var, NS_DISCO_ITEMS))
  35. capabilities |= JABBER_CAP_ITEMS;
  36. - else if(!strcmp(var, "http://jabber.org/protocol/commands")) {
  37. + else if(!strcmp(var, "http://jabber.org/protocol/commands"))
  38. capabilities |= JABBER_CAP_ADHOC;
  39. - }
  40. else if(!strcmp(var, NS_IBB)) {
  41. purple_debug_info("jabber", "remote supports IBB\n");
  42. capabilities |= JABBER_CAP_IBB;
  43. }
  44. + else if(!strcmp(var, NS_XMPP_CARBONS))
  45. + capabilities |= JABBER_CAP_CARBONS;
  46. + else if(!strcmp(var, NS_XMPP_MAM))
  47. + capabilities |= JABBER_CAP_MAM;
  48. }
  49. }
  50.  
  51. @@ -386,6 +390,29 @@
  52. jabber_request_block_list(js);
  53. }
  54.  
  55. + if ((js->server_caps & JABBER_CAP_CARBONS) && purple_account_get_bool(js->gc->account, "carbons", FALSE)) {
  56. + JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET);
  57. + xmlnode *enable = xmlnode_new_child(iq->node, "enable");
  58. +
  59. + purple_debug_info("jabber", "Automatically enabling Carbons.\n");
  60. +
  61. + xmlnode_set_namespace(enable, NS_XMPP_CARBONS);
  62. +
  63. + jabber_iq_send(iq);
  64. + }
  65. +
  66. + if ((js->server_caps & JABBER_CAP_MAM) && purple_account_get_bool(js->gc->account, "mam", FALSE)) {
  67. + purple_debug_info("jabber", "MAM Requesting.\n");
  68. +
  69. + time_t mam_laststamp = (time_t *)purple_account_get_int(js->gc->account, "mam_laststamp", time(0));
  70. + purple_account_set_int(js->gc->account, "mam_laststamp", mam_laststamp + 1);
  71. +
  72. + const struct tm *unixtime = gmtime(&mam_laststamp);
  73. + strcpy(js->mam->last_timestamp, purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", unixtime));
  74. +
  75. + jabber_mam_add_to_queue(js, js->mam->last_timestamp, NULL, NULL);
  76. + }
  77. +
  78. /* If there are manually specified bytestream proxies, query them */
  79. ft_proxies = purple_account_get_string(js->gc->account, "ft_proxies", NULL);
  80. if (ft_proxies) {
  81. @@ -574,6 +601,10 @@
  82. js->server_caps |= JABBER_CAP_ADHOC;
  83. } else if (!strcmp(NS_SIMPLE_BLOCKING, var)) {
  84. js->server_caps |= JABBER_CAP_BLOCKING;
  85. + } else if(!strcmp(var, NS_XMPP_CARBONS)) {
  86. + js->server_caps |= JABBER_CAP_CARBONS;
  87. + } else if(!strcmp(var, NS_XMPP_MAM)) {
  88. + js->server_caps |= JABBER_CAP_MAM;
  89. }
  90. }
  91.  
  92. --- a/libpurple/protocols/jabber/jabber.c
  93. +++ b/libpurple/protocols/jabber/jabber.c
  94. @@ -933,6 +933,7 @@
  95. js = gc->proto_data = g_new0(JabberStream, 1);
  96. js->gc = gc;
  97. js->fd = -1;
  98. + js->mam = calloc(1, sizeof(mam_t));
  99.  
  100. if (g_strcmp0("prpl-facebook-xmpp",
  101. purple_account_get_protocol_id(account)) == 0)
  102. @@ -1731,6 +1732,10 @@
  103. js->google_relay_requests);
  104. }
  105. }
  106. +
  107. + jabber_mam_clear(js->mam);
  108. + free(js->mam);
  109. + js->mam = NULL;
  110.  
  111. g_free(js);
  112.  
  113. @@ -2574,6 +2579,8 @@
  114. JabberStream *js = gc->proto_data;
  115. GList *m = NULL;
  116. PurplePluginAction *act;
  117. + gboolean has_carbons = purple_account_get_bool(gc->account, "carbons", FALSE);
  118. + gboolean has_mam = purple_account_get_bool(gc->account, "mam", FALSE);
  119.  
  120. act = purple_plugin_action_new(_("Set User Info..."),
  121. jabber_setup_set_info);
  122. @@ -2597,6 +2604,16 @@
  123. if(js->commands)
  124. jabber_adhoc_init_server_commands(js, &m);
  125.  
  126. + if(js->server_caps & JABBER_CAP_CARBONS) {
  127. + act = purple_plugin_action_new((has_carbons ? _("Disable Message Copies") : _("Enable Message Copies")), jabber_toggle_carbons);
  128. + m = g_list_append(m, act);
  129. + }
  130. +
  131. + if(js->server_caps & JABBER_CAP_MAM) {
  132. + act = purple_plugin_action_new((has_mam ? _("Disable Messaging Archive Management") : _("Enable Messaging Archive Management")), jabber_toggle_mam);
  133. + m = g_list_append(m, act);
  134. + }
  135. +
  136. return m;
  137. }
  138.  
  139. --- a/libpurple/protocols/jabber/jabber.h
  140. +++ b/libpurple/protocols/jabber/jabber.h
  141. @@ -48,9 +48,12 @@
  142.  
  143. JABBER_CAP_ITEMS = 1 << 14,
  144. JABBER_CAP_ROSTER_VERSIONING = 1 << 15,
  145. -
  146. +
  147. JABBER_CAP_FACEBOOK = 1 << 16,
  148.  
  149. + JABBER_CAP_CARBONS = 1 << 17,
  150. + JABBER_CAP_MAM = 1 << 18,
  151. +
  152. JABBER_CAP_RETRIEVED = 1 << 31
  153. } JabberCapabilities;
  154.  
  155. @@ -62,6 +65,7 @@
  156. #include "connection.h"
  157. #include "dnsquery.h"
  158. #include "dnssrv.h"
  159. +#include "mam.h"
  160. #include "media.h"
  161. #include "mediamanager.h"
  162. #include "roomlist.h"
  163. @@ -287,6 +291,8 @@
  164.  
  165. /* facebook quirks */
  166. gboolean facebook_roster_cleanup_performed;
  167. +
  168. + mam_t *mam;
  169. };
  170.  
  171. typedef gboolean (JabberFeatureEnabled)(JabberStream *js, const gchar *namespace);
  172. --- /dev/null
  173. +++ b/libpurple/protocols/jabber/mam.c
  174. @@ -0,0 +1,245 @@
  175. +/*
  176. + * purple - Jabber Protocol Plugin
  177. + *
  178. + * Purple is the legal property of its developers, whose names are too numerous
  179. + * to list here. Please refer to the COPYRIGHT file distributed with this
  180. + * source distribution.
  181. + *
  182. + * This program is free software; you can redistribute it and/or modify
  183. + * it under the terms of the GNU General Public License as published by
  184. + * the Free Software Foundation; either version 2 of the License, or
  185. + * (at your option) any later version.
  186. + *
  187. + * This program is distributed in the hope that it will be useful,
  188. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  189. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  190. + * GNU General Public License for more details.
  191. + *
  192. + * You should have received a copy of the GNU General Public License
  193. + * along with this program; if not, write to the Free Software
  194. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
  195. + *
  196. + */
  197. +
  198. +#include "internal.h"
  199. +#include "request.h"
  200. +
  201. +#include "jabber.h"
  202. +#include "mam.h"
  203. +
  204. +struct list_s
  205. +{
  206. + void *data;
  207. + list_t *prev;
  208. + list_t *next;
  209. +};
  210. +
  211. +list_t * list_append(list_t *li, void *data)
  212. +{
  213. + list_t *nli = malloc(sizeof(list_t));
  214. + nli->data = data;
  215. + if(!li) {
  216. + nli->prev = nli->next = NULL;
  217. + } else {
  218. + nli->prev = li;
  219. + nli->next = li->next;
  220. + if(li->next)
  221. + li->next->prev = nli;
  222. + li->next = nli;
  223. + }
  224. + return nli;
  225. +}
  226. +
  227. +list_t * list_insert(list_t *li, void *data)
  228. +{
  229. + list_t *nli = malloc(sizeof(list_t));
  230. + nli->data = data;
  231. + if(!li) {
  232. + nli->prev = nli->next = NULL;
  233. + } else {
  234. + nli->next = li;
  235. + nli->prev = li->prev;
  236. + if(li->prev)
  237. + li->prev->next = nli;
  238. + li->prev = nli;
  239. + }
  240. + return nli;
  241. +}
  242. +
  243. +list_t * list_delete(list_t *li, void *data)
  244. +{
  245. + if(!li)
  246. + return NULL;
  247. +
  248. + list_t *i = li;
  249. + if(data) {
  250. + i = list_get_first(li);
  251. + while(i) {
  252. + if(data == list_get_data(i))
  253. + break;
  254. + i = i->next;
  255. + }
  256. + if(!i)
  257. + return li;
  258. + }
  259. +
  260. + list_t *r = NULL;
  261. + if(i->next) {
  262. + i->next->prev = i->prev;
  263. + r = i->next;
  264. + }
  265. + if(i->prev) {
  266. + i->prev->next = i->next;
  267. + r = i->prev;
  268. + }
  269. + free(i);
  270. + return r;
  271. +}
  272. +
  273. +inline list_t * list_get_first(list_t *li)
  274. +{
  275. + if(!li)
  276. + return NULL;
  277. + while(li->prev)
  278. + li = li->prev;
  279. + return li;
  280. +}
  281. +
  282. +inline list_t * list_get_next(list_t *li)
  283. +{
  284. + return li->next;
  285. +}
  286. +
  287. +inline void * list_get_data(list_t *li)
  288. +{
  289. + return li->data;
  290. +}
  291. +
  292. +void jabber_mam_clear(mam_t *mam)
  293. +{
  294. + if (mam)
  295. + return;
  296. +
  297. + list_t *queue_item = list_get_first(mam->queue);
  298. + while (queue_item) {
  299. + mam_item_t *mam_item = list_get_data(queue_item);
  300. +
  301. + free(mam_item->start);
  302. + free(mam_item->end);
  303. + free(mam_item->with);
  304. + free(mam_item);
  305. +
  306. + queue_item = list_get_next(queue_item);
  307. + }
  308. +}
  309. +
  310. +void jabber_mam_add_to_queue(JabberStream *js, const char* start, const char* end, const char* with)
  311. +{
  312. + if (!js->mam)
  313. + return;
  314. +
  315. + mam_item_t *mam_item = calloc(1, sizeof(mam_item_t));
  316. +
  317. + if (start) {
  318. + mam_item->start = calloc(1, strlen(start) + 1);
  319. + strcpy(mam_item->start, start);
  320. + }
  321. +
  322. + if (end) {
  323. + mam_item->end = calloc(1, strlen(end) + 1);
  324. + strcpy(mam_item->end, end);
  325. + }
  326. +
  327. + if (with) {
  328. + mam_item->with = calloc(1, strlen(with) + 1);
  329. + strcpy(mam_item->with, with);
  330. + }
  331. +
  332. + js->mam->queue = list_append(js->mam->queue, mam_item);
  333. +
  334. + jabber_mam_process(js, NULL);
  335. +}
  336. +
  337. +void jabber_mam_process(JabberStream *js, const char* after)
  338. +{
  339. + if (!js->mam)
  340. + return;
  341. +
  342. + if (js->mam->current && js->mam->current->completed) {
  343. + free(js->mam->current->start);
  344. + free(js->mam->current->end);
  345. + free(js->mam->current->with);
  346. +
  347. + memset(js->mam->last_timestamp, 0, 32);
  348. +
  349. + free(js->mam->current);
  350. + js->mam->current = NULL;
  351. + }
  352. +
  353. + if (!js->mam->current) {
  354. + list_t *queue_item = list_get_first(js->mam->queue);
  355. + if (queue_item) {
  356. + js->mam->queue = list_delete(js->mam->queue, queue_item);
  357. +
  358. + js->mam->current = list_get_data(queue_item);
  359. +
  360. + js->mam->queue = list_get_next(js->mam->queue);
  361. + }
  362. + }
  363. +
  364. + if (js->mam->current)
  365. + jabber_mam_request(js, after);
  366. +}
  367. +
  368. +void jabber_mam_request(JabberStream *js, const char* after)
  369. +{
  370. + if (!js->mam)
  371. + return;
  372. +
  373. + JabberIq *iq = jabber_iq_new_query(js, JABBER_IQ_SET, NS_XMPP_MAM);
  374. + xmlnode *query = xmlnode_get_child(iq->node, "query");
  375. +
  376. + xmlnode *x = xmlnode_new_child(query, "x");
  377. + xmlnode_set_namespace(x, "jabber:x:data");
  378. +
  379. + xmlnode *field = xmlnode_new_child(x, "field");
  380. + xmlnode_set_attrib(field, "type", "hidden");
  381. + xmlnode_set_attrib(field, "var", "FORM_TYPE");
  382. + xmlnode *value = xmlnode_new_child(field, "value");
  383. + xmlnode_insert_data(value, NS_XMPP_MAM, -1);
  384. +
  385. + if (after) {
  386. + xmlnode *set = xmlnode_new_child(query, "set");
  387. + xmlnode_set_namespace(set, NS_RSM);
  388. +
  389. + value = xmlnode_new_child(set, "after");
  390. + xmlnode_insert_data(value, after, -1);
  391. + }
  392. +
  393. + if (js->mam->current->start) {
  394. + field = xmlnode_new_child(x, "field");
  395. + xmlnode_set_attrib(field, "var", "start");
  396. +
  397. + value = xmlnode_new_child(field, "value");
  398. + xmlnode_insert_data(value, js->mam->current->start, -1);
  399. + }
  400. +
  401. + if (js->mam->current->end) {
  402. + field = xmlnode_new_child(x, "field");
  403. + xmlnode_set_attrib(field, "var", "end");
  404. +
  405. + value = xmlnode_new_child(field, "value");
  406. + xmlnode_insert_data(value, js->mam->current->end, -1);
  407. + }
  408. +
  409. + if (js->mam->current->with) {
  410. + field = xmlnode_new_child(x, "field");
  411. + xmlnode_set_attrib(field, "var", "with");
  412. +
  413. + value = xmlnode_new_child(field, "value");
  414. + xmlnode_insert_data(value, js->mam->current->with, -1);
  415. + }
  416. +
  417. + jabber_iq_send(iq);
  418. +}
  419. +
  420. --- /dev/null
  421. +++ b/libpurple/protocols/jabber/mam.h
  422. @@ -0,0 +1,56 @@
  423. +/*
  424. + * purple - Jabber Protocol Plugin
  425. + *
  426. + * Purple is the legal property of its developers, whose names are too numerous
  427. + * to list here. Please refer to the COPYRIGHT file distributed with this
  428. + * source distribution.
  429. + *
  430. + * This program is free software; you can redistribute it and/or modify
  431. + * it under the terms of the GNU General Public License as published by
  432. + * the Free Software Foundation; either version 2 of the License, or
  433. + * (at your option) any later version.
  434. + *
  435. + * This program is distributed in the hope that it will be useful,
  436. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  437. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  438. + * GNU General Public License for more details.
  439. + *
  440. + * You should have received a copy of the GNU General Public License
  441. + * along with this program; if not, write to the Free Software
  442. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
  443. + *
  444. + */
  445. +
  446. +#ifndef PURPLE_JABBER_MAM_H_
  447. +#define PURPLE_JABBER_MAM_H_
  448. +
  449. +#include "xmlnode.h"
  450. +
  451. +typedef struct list_s list_t;
  452. +
  453. +list_t * list_append(list_t *, void *);
  454. +list_t * list_insert(list_t *, void *);
  455. +list_t * list_delete(list_t *, void *);
  456. +list_t * list_get_first(list_t *);
  457. +list_t * list_get_next(list_t *);
  458. +void * list_get_data(list_t *);
  459. +
  460. +typedef struct {
  461. + char *start;
  462. + char *end;
  463. + char *with;
  464. + gboolean completed;
  465. +} mam_item_t;
  466. +
  467. +typedef struct {
  468. + list_t *queue;
  469. + mam_item_t *current;
  470. + char last_timestamp[32];
  471. +} mam_t;
  472. +
  473. +void jabber_mam_clear(mam_t *mam);
  474. +void jabber_mam_add_to_queue(JabberStream *js, const char* start, const char* end, const char* with);
  475. +void jabber_mam_process(JabberStream *js, const char* after);
  476. +void jabber_mam_request(JabberStream *js, const char* after);
  477. +
  478. +#endif /* PURPLE_JABBER_MAM_H_ */
  479. --- a/libpurple/protocols/jabber/message.c
  480. +++ b/libpurple/protocols/jabber/message.c
  481. @@ -31,6 +31,7 @@
  482. #include "chat.h"
  483. #include "data.h"
  484. #include "google/google.h"
  485. +#include "mam.h"
  486. #include "message.h"
  487. #include "xmlnode.h"
  488. #include "pep.h"
  489. @@ -58,7 +59,8 @@
  490.  
  491. static void handle_chat(JabberMessage *jm)
  492. {
  493. - JabberID *jid = jabber_id_new(jm->from);
  494. + gchar *contact = jm->outgoing ? jm->to : jm->from;
  495. + JabberID *jid = jabber_id_new(contact);
  496.  
  497. PurpleConnection *gc;
  498. PurpleAccount *account;
  499. @@ -71,48 +73,50 @@
  500. gc = jm->js->gc;
  501. account = purple_connection_get_account(gc);
  502.  
  503. - jb = jabber_buddy_find(jm->js, jm->from, TRUE);
  504. + jb = jabber_buddy_find(jm->js, contact, TRUE);
  505. jbr = jabber_buddy_find_resource(jb, jid->resource);
  506.  
  507. if(!jm->xhtml && !jm->body) {
  508. - if (jbr && jm->chat_state != JM_STATE_NONE)
  509. - jbr->chat_states = JABBER_CHAT_STATES_SUPPORTED;
  510. -
  511. - if(JM_STATE_COMPOSING == jm->chat_state) {
  512. - serv_got_typing(gc, jm->from, 0, PURPLE_TYPING);
  513. - } else if(JM_STATE_PAUSED == jm->chat_state) {
  514. - serv_got_typing(gc, jm->from, 0, PURPLE_TYPED);
  515. - } else if(JM_STATE_GONE == jm->chat_state) {
  516. - PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
  517. - jm->from, account);
  518. - if (conv && jid->node && jid->domain) {
  519. - char buf[256];
  520. - PurpleBuddy *buddy;
  521. -
  522. - g_snprintf(buf, sizeof(buf), "%s@%s", jid->node, jid->domain);
  523. -
  524. - if ((buddy = purple_find_buddy(account, buf))) {
  525. - const char *who;
  526. - char *escaped;
  527. -
  528. - who = purple_buddy_get_alias(buddy);
  529. - escaped = g_markup_escape_text(who, -1);
  530. -
  531. - g_snprintf(buf, sizeof(buf),
  532. - _("%s has left the conversation."), escaped);
  533. - g_free(escaped);
  534. -
  535. - /* At some point when we restructure PurpleConversation,
  536. - * this should be able to be implemented by removing the
  537. - * user from the conversation like we do with chats now. */
  538. - purple_conversation_write(conv, "", buf,
  539. - PURPLE_MESSAGE_SYSTEM, time(NULL));
  540. + if (!jm->outgoing) {
  541. + if (jbr && jm->chat_state != JM_STATE_NONE)
  542. + jbr->chat_states = JABBER_CHAT_STATES_SUPPORTED;
  543. +
  544. + if(JM_STATE_COMPOSING == jm->chat_state) {
  545. + serv_got_typing(gc, contact, 0, PURPLE_TYPING);
  546. + } else if(JM_STATE_PAUSED == jm->chat_state) {
  547. + serv_got_typing(gc, contact, 0, PURPLE_TYPED);
  548. + } else if(JM_STATE_GONE == jm->chat_state) {
  549. + PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
  550. + contact, account);
  551. + if (conv && jid->node && jid->domain) {
  552. + char buf[256];
  553. + PurpleBuddy *buddy;
  554. +
  555. + g_snprintf(buf, sizeof(buf), "%s@%s", jid->node, jid->domain);
  556. +
  557. + if ((buddy = purple_find_buddy(account, buf))) {
  558. + const char *who;
  559. + char *escaped;
  560. +
  561. + who = purple_buddy_get_alias(buddy);
  562. + escaped = g_markup_escape_text(who, -1);
  563. +
  564. + g_snprintf(buf, sizeof(buf),
  565. + _("%s has left the conversation."), escaped);
  566. + g_free(escaped);
  567. +
  568. + /* At some point when we restructure PurpleConversation,
  569. + * this should be able to be implemented by removing the
  570. + * user from the conversation like we do with chats now. */
  571. + purple_conversation_write(conv, "", buf,
  572. + PURPLE_MESSAGE_SYSTEM, time(NULL));
  573. + }
  574. }
  575. - }
  576. - serv_got_typing_stopped(gc, jm->from);
  577. + serv_got_typing_stopped(gc, contact);
  578.  
  579. - } else {
  580. - serv_got_typing_stopped(gc, jm->from);
  581. + } else {
  582. + serv_got_typing_stopped(gc, contact);
  583. + }
  584. }
  585. } else {
  586. if (jid->resource) {
  587. @@ -128,12 +132,12 @@
  588. PurpleConversation *conv;
  589.  
  590. conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM,
  591. - jm->from, account);
  592. - if (conv && !g_str_equal(jm->from,
  593. + contact, account);
  594. + if (conv && !g_str_equal(contact,
  595. purple_conversation_get_name(conv))) {
  596. purple_debug_info("jabber", "Binding conversation to %s\n",
  597. - jm->from);
  598. - purple_conversation_set_name(conv, jm->from);
  599. + contact);
  600. + purple_conversation_set_name(conv, contact);
  601. }
  602. }
  603.  
  604. @@ -156,7 +160,8 @@
  605. jm->body = jabber_google_format_to_html(jm->body);
  606. g_free(tmp);
  607. }
  608. - serv_got_im(gc, jm->from, jm->xhtml ? jm->xhtml : jm->body, 0, jm->sent);
  609. + serv_got_im(gc, contact, jm->xhtml ? jm->xhtml : jm->body,
  610. + (jm->outgoing ? PURPLE_MESSAGE_SEND : PURPLE_MESSAGE_RECV), jm->sent);
  611. }
  612.  
  613. jabber_id_free(jid);
  614. @@ -502,7 +507,88 @@
  615. JabberMessage *jm;
  616. const char *id, *from, *to, *type;
  617. xmlnode *child;
  618. - gboolean signal_return;
  619. + gboolean signal_return, is_outgoing = FALSE;
  620. + time_t message_timestamp = time(NULL);
  621. + gboolean delayed = FALSE;
  622. +
  623. + /* Check if this is a carbon-copy of a message.
  624. + * If so, use that instead for the rest of this function,
  625. + * but keep track of wether the from and to should be swapped.
  626. + */
  627. + from = xmlnode_get_attrib(packet, "from");
  628. +
  629. + if (jabber_is_own_account(js, from)) {
  630. + xmlnode *received = xmlnode_get_child_with_namespace(packet, "received", NS_XMPP_CARBONS);
  631. + xmlnode *sent = xmlnode_get_child_with_namespace(packet, "sent", NS_XMPP_CARBONS);
  632. + xmlnode *result = xmlnode_get_child_with_namespace(packet, "result", NS_XMPP_MAM);
  633. + xmlnode *fin = xmlnode_get_child_with_namespace(packet, "fin", NS_XMPP_MAM);
  634. +
  635. + if (received || sent || result) {
  636. + xmlnode *forwarded = xmlnode_get_child_with_namespace(received ? received : sent ? sent : result, "forwarded", NS_XMPP_FORWARD);
  637. +
  638. + if (forwarded) {
  639. + xmlnode *message = xmlnode_get_child_with_namespace(forwarded, "message", NS_XMPP_CLIENT);
  640. + xmlnode *delay = xmlnode_get_child_with_namespace(forwarded, "delay", NS_DELAYED_DELIVERY);
  641. +
  642. + if (message) {
  643. + purple_debug_info("jabber", "It's forwarded message, using the wrapped message instead.\n");
  644. + packet = message;
  645. +
  646. + from = xmlnode_get_attrib(packet, "from");
  647. +
  648. + if (result) {
  649. + JabberID *jid = jabber_id_new(from);
  650. +
  651. + if (!jid)
  652. + return;
  653. +
  654. + gboolean equal = (purple_strequal(jid->node, js->user->node) &&
  655. + g_str_equal(jid->domain, js->user->domain));
  656. +
  657. + if (equal)
  658. + is_outgoing = TRUE;
  659. +
  660. + jabber_id_free(jid);
  661. + }
  662. + else if (sent)
  663. + is_outgoing = TRUE;
  664. +
  665. + if (delay) {
  666. + const char *timestamp = xmlnode_get_attrib(delay, "stamp");
  667. +
  668. + if(timestamp) {
  669. + if (result) {
  670. + memset(js->mam->last_timestamp, 0, 32);
  671. + strcpy(js->mam->last_timestamp, timestamp);
  672. + }
  673. +
  674. + purple_debug_info("jabber", "Found a delay stamp: %s\n", timestamp);
  675. +
  676. + delayed = TRUE;
  677. +
  678. + message_timestamp = purple_str_to_time(timestamp, TRUE, NULL, NULL, NULL);
  679. + }
  680. + }
  681. + }
  682. + }
  683. + } else if (fin) {
  684. + gboolean complete = xmlnode_get_attrib(fin, "complete") ? TRUE : FALSE;
  685. + if (complete) {
  686. + js->mam->current->completed = TRUE;
  687. +
  688. + jabber_mam_process(js, NULL);
  689. + } else {
  690. + xmlnode *set = xmlnode_get_child_with_namespace(fin, "set", NS_RSM);
  691. + if (set) {
  692. + xmlnode *last = xmlnode_get_child(set, "last");
  693. + if (last) {
  694. + jabber_mam_process(js, xmlnode_get_data(last));
  695. + }
  696. + }
  697. + }
  698. + return;
  699. + }
  700. + }
  701.  
  702. from = xmlnode_get_attrib(packet, "from");
  703. id = xmlnode_get_attrib(packet, "id");
  704. @@ -516,9 +602,13 @@
  705.  
  706. jm = g_new0(JabberMessage, 1);
  707. jm->js = js;
  708. - jm->sent = time(NULL);
  709. - jm->delayed = FALSE;
  710. + jm->sent = message_timestamp;
  711. + jm->delayed = delayed;
  712. jm->chat_state = JM_STATE_NONE;
  713. + jm->outgoing = is_outgoing;
  714. +
  715. + if (jm->sent > purple_account_get_int(js->gc->account, "mam_laststamp", 0))
  716. + purple_account_set_int(js->gc->account, "mam_laststamp", jm->sent);
  717.  
  718. if(type) {
  719. if(!strcmp(type, "normal"))
  720. @@ -624,12 +714,12 @@
  721. jm->type == JABBER_MESSAGE_CHAT) {
  722. conv =
  723. purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY,
  724. - from, account);
  725. + is_outgoing ? to : from, account);
  726. if (!conv) {
  727. /* we need to create the conversation here */
  728. conv =
  729. purple_conversation_new(PURPLE_CONV_TYPE_IM,
  730. - account, from);
  731. + account, is_outgoing ? to : from);
  732. }
  733. }
  734. }
  735. @@ -709,6 +799,7 @@
  736. } else if(!strcmp(child->name, "attention") && !strcmp(xmlns, NS_ATTENTION)) {
  737. jm->hasBuzz = TRUE;
  738. } else if(!strcmp(child->name, "delay") && !strcmp(xmlns, NS_DELAYED_DELIVERY)) {
  739. + /* Carbons/Stanza fowarding might have already set jm->delayed. However, this timestamp was certainly applied earlier, so it overrides Carbons. */
  740. const char *timestamp = xmlnode_get_attrib(child, "stamp");
  741. jm->delayed = TRUE;
  742. if(timestamp)
  743. @@ -1085,6 +1176,8 @@
  744. }
  745. }
  746.  
  747. + purple_account_set_int(jm->js->gc->account, "mam_laststamp", time(0));
  748. +
  749. jabber_send(jm->js, message);
  750.  
  751. xmlnode_free(message);
  752. @@ -1305,3 +1398,48 @@
  753.  
  754. return purple_account_get_bool(account, "custom_smileys", TRUE);
  755. }
  756. +
  757. +void jabber_toggle_carbons(PurplePluginAction *action) {
  758. + PurpleConnection *gc = (PurpleConnection *) action->context;
  759. + JabberStream *js = purple_connection_get_protocol_data(gc);
  760. + JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET);
  761. + gboolean has_carbons = !purple_account_get_bool(purple_connection_get_account(gc), "carbons", FALSE);
  762. + xmlnode *node;
  763. +
  764. + if (has_carbons) {
  765. + node = xmlnode_new_child(iq->node, "enable");
  766. + } else {
  767. + node = xmlnode_new_child(iq->node, "disable");
  768. + }
  769. +
  770. + purple_account_set_bool(gc->account, "carbons", has_carbons);
  771. +
  772. + xmlnode_set_namespace(node, NS_XMPP_CARBONS);
  773. + jabber_iq_send(iq);
  774. +
  775. + /* Force an update of the account actions. */
  776. + purple_prpl_got_account_actions(purple_connection_get_account(gc));
  777. +}
  778. +
  779. +void jabber_toggle_mam(PurplePluginAction *action) {
  780. + PurpleConnection *gc = (PurpleConnection *) action->context;
  781. + JabberStream *js = purple_connection_get_protocol_data(gc);
  782. + gboolean has_mam = !purple_account_get_bool(purple_connection_get_account(gc), "mam", FALSE);
  783. +
  784. + purple_account_set_bool(gc->account, "mam", has_mam);
  785. +
  786. + if (has_mam) {
  787. + purple_debug_info("jabber", "MAM Requesting.\n");
  788. +
  789. + time_t mam_laststamp = (time_t *)purple_account_get_int(js->gc->account, "mam_laststamp", time(0));
  790. + purple_account_set_int(js->gc->account, "mam_laststamp", mam_laststamp);
  791. +
  792. + const struct tm *unixtime = gmtime(&mam_laststamp);
  793. + strcpy(js->mam->last_timestamp, purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", unixtime));
  794. +
  795. + jabber_mam_add_to_queue(js, js->mam->last_timestamp, NULL, NULL);
  796. + }
  797. +
  798. + /* Force an update of the account actions. */
  799. + purple_prpl_got_account_actions(purple_connection_get_account(gc));
  800. +}
  801. --- a/libpurple/protocols/jabber/message.h
  802. +++ b/libpurple/protocols/jabber/message.h
  803. @@ -62,6 +62,7 @@
  804. } chat_state;
  805. GList *etc;
  806. GList *eventitems;
  807. + gboolean outgoing;
  808. } JabberMessage;
  809.  
  810. void jabber_message_free(JabberMessage *jm);
  811. @@ -79,4 +80,7 @@
  812.  
  813. gboolean jabber_custom_smileys_isenabled(JabberStream *js, const const gchar *namespace);
  814.  
  815. +void jabber_toggle_carbons(PurplePluginAction *action);
  816. +void jabber_toggle_mam(PurplePluginAction *action);
  817. +
  818. #endif /* PURPLE_JABBER_MESSAGE_H_ */
  819. --- a/libpurple/protocols/jabber/namespaces.h
  820. +++ b/libpurple/protocols/jabber/namespaces.h
  821. @@ -42,6 +42,9 @@
  822. /* XEP-0047 IBB (In-band bytestreams) */
  823. #define NS_IBB "http://jabber.org/protocol/ibb"
  824.  
  825. +/* XEP-0059 Result Set Management (RSM) */
  826. +#define NS_RSM "http://jabber.org/protocol/rsm"
  827. +
  828. /* XEP-0065 SOCKS5 Bytestreams */
  829. #define NS_BYTESTREAMS "http://jabber.org/protocol/bytestreams"
  830.  
  831. @@ -95,6 +98,15 @@
  832. /* XEP-0264 File Transfer Thumbnails (Thumbs) */
  833. #define NS_THUMBS "urn:xmpp:thumbs:0"
  834.  
  835. +/* XEP-0280 Message Carbons */
  836. +#define NS_XMPP_CARBONS "urn:xmpp:carbons:2"
  837. +
  838. +/* XEP-0297 Message Forwarding */
  839. +#define NS_XMPP_FORWARD "urn:xmpp:forward:0"
  840. +
  841. +/* XEP-0313 Message Archive Management */
  842. +#define NS_XMPP_MAM "urn:xmpp:mam:0"
  843. +
  844. /* Google extensions */
  845. #define NS_GOOGLE_CAMERA "http://www.google.com/xmpp/protocol/camera/v1"
  846. #define NS_GOOGLE_VIDEO "http://www.google.com/xmpp/protocol/video/v1"
  847. --- a/libpurple/server.c
  848. +++ b/libpurple/server.c
  849. @@ -575,11 +575,6 @@
  850. mtime = time(NULL);
  851. }
  852.  
  853. - /*
  854. - * XXX: Should we be setting this here, or relying on prpls to set it?
  855. - */
  856. - flags |= PURPLE_MESSAGE_RECV;
  857. -
  858. if (!purple_privacy_check(account, who)) {
  859. purple_signal_emit(purple_conversations_get_handle(), "blocked-im-msg",
  860. account, who, msg, flags, (unsigned int)mtime);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement