libpurple/protocols/jabber/message.c

changeset 38358
30ba44276e74
parent 38298
f0a8f63f9312
parent 38264
99356e68aff5
child 39065
3997b9da75e8
equal deleted inserted replaced
38346:dee30d35e5e7 38358:30ba44276e74
44 typedef struct { 44 typedef struct {
45 PurpleConversation *conv; 45 PurpleConversation *conv;
46 gchar *shortcut; 46 gchar *shortcut;
47 } JabberMessageRemoteSmileyAddData; 47 } JabberMessageRemoteSmileyAddData;
48 48
49 static GString *jm_body_with_oob(JabberMessage *jm) {
50 GList *etc;
51 GString *body = g_string_new("");
52
53 if(jm->xhtml)
54 g_string_append(body, jm->xhtml);
55 else if(jm->body)
56 g_string_append(body, jm->body);
57
58 for(etc = jm->etc; etc; etc = etc->next) {
59 PurpleXmlNode *x = etc->data;
60 const char *xmlns = purple_xmlnode_get_namespace(x);
61 if(purple_strequal(xmlns, NS_OOB_X_DATA)) {
62 PurpleXmlNode *url, *desc;
63 char *urltxt, *desctxt;
64
65 url = purple_xmlnode_get_child(x, "url");
66 desc = purple_xmlnode_get_child(x, "desc");
67
68 if(!url)
69 continue;
70
71 urltxt = purple_xmlnode_get_data(url);
72 desctxt = desc ? purple_xmlnode_get_data(desc) : urltxt;
73
74 if(body->len && !purple_strequal(body->str, urltxt))
75 g_string_append_printf(body, "<br/><a href='%s'>%s</a>",
76 urltxt, desctxt);
77 else
78 g_string_printf(body, "<a href='%s'>%s</a>",
79 urltxt, desctxt);
80
81 g_free(urltxt);
82
83 if(desctxt != urltxt)
84 g_free(desctxt);
85 }
86 }
87
88 return body;
89 }
90
49 void jabber_message_free(JabberMessage *jm) 91 void jabber_message_free(JabberMessage *jm)
50 { 92 {
51 g_free(jm->from); 93 g_free(jm->from);
52 g_free(jm->to); 94 g_free(jm->to);
53 g_free(jm->id); 95 g_free(jm->id);
69 111
70 PurpleConnection *gc; 112 PurpleConnection *gc;
71 PurpleAccount *account; 113 PurpleAccount *account;
72 JabberBuddy *jb; 114 JabberBuddy *jb;
73 JabberBuddyResource *jbr; 115 JabberBuddyResource *jbr;
116 GString *body;
74 117
75 if(!jid) 118 if(!jid)
76 return; 119 return;
77 120
78 gc = jm->js->gc; 121 gc = jm->js->gc;
79 account = purple_connection_get_account(gc); 122 account = purple_connection_get_account(gc);
80 123
81 jb = jabber_buddy_find(jm->js, jm->from, TRUE); 124 jb = jabber_buddy_find(jm->js, jm->from, TRUE);
82 jbr = jabber_buddy_find_resource(jb, jid->resource); 125 jbr = jabber_buddy_find_resource(jb, jid->resource);
83 126
84 if(!jm->xhtml && !jm->body) { 127 if (jbr && jm->chat_state != JM_STATE_NONE)
85 if (jbr && jm->chat_state != JM_STATE_NONE) 128 jbr->chat_states = JABBER_CHAT_STATES_SUPPORTED;
86 jbr->chat_states = JABBER_CHAT_STATES_SUPPORTED; 129
87 130 switch(jm->chat_state) {
88 if(JM_STATE_COMPOSING == jm->chat_state) { 131 case JM_STATE_COMPOSING:
89 purple_serv_got_typing(gc, jm->from, 0, PURPLE_IM_TYPING); 132 purple_serv_got_typing(gc, jm->from, 0, PURPLE_IM_TYPING);
90 } else if(JM_STATE_PAUSED == jm->chat_state) { 133 break;
134 case JM_STATE_PAUSED:
91 purple_serv_got_typing(gc, jm->from, 0, PURPLE_IM_TYPED); 135 purple_serv_got_typing(gc, jm->from, 0, PURPLE_IM_TYPED);
92 } else if(JM_STATE_GONE == jm->chat_state) { 136 break;
137 case JM_STATE_GONE: {
93 PurpleIMConversation *im = purple_conversations_find_im_with_account( 138 PurpleIMConversation *im = purple_conversations_find_im_with_account(
94 jm->from, account); 139 jm->from, account);
95 if (im && jid->node && jid->domain) { 140 if (im && jid->node && jid->domain) {
96 char buf[256]; 141 char buf[256];
97 PurpleBuddy *buddy; 142 PurpleBuddy *buddy;
115 purple_conversation_write_system_message( 160 purple_conversation_write_system_message(
116 PURPLE_CONVERSATION(im), buf, 0); 161 PURPLE_CONVERSATION(im), buf, 0);
117 } 162 }
118 } 163 }
119 purple_serv_got_typing_stopped(gc, jm->from); 164 purple_serv_got_typing_stopped(gc, jm->from);
120 165 break;
121 } else { 166 }
167 default:
122 purple_serv_got_typing_stopped(gc, jm->from); 168 purple_serv_got_typing_stopped(gc, jm->from);
123 } 169 }
124 } else { 170
171 if (jm->js->googletalk && jm->body && jm->xhtml == NULL) {
172 char *tmp = jm->body;
173 jm->body = jabber_google_format_to_html(jm->body);
174 g_free(tmp);
175 }
176
177 body = jm_body_with_oob(jm);
178
179 if(body && body->len) {
125 if (jid->resource) { 180 if (jid->resource) {
126 /* 181 /*
127 * We received a message from a specific resource, so 182 * We received a message from a specific resource, so
128 * we probably want a reply to go to this specific 183 * we probably want a reply to go to this specific
129 * resource (i.e. bind/lock the conversation to this 184 * resource (i.e. bind/lock the conversation to this
133 * from purple_conversation_get_name() 188 * from purple_conversation_get_name()
134 */ 189 */
135 PurpleIMConversation *im; 190 PurpleIMConversation *im;
136 191
137 im = purple_conversations_find_im_with_account(jm->from, account); 192 im = purple_conversations_find_im_with_account(jm->from, account);
138 if (im && !g_str_equal(jm->from, 193 if (im && !purple_strequal(jm->from,
139 purple_conversation_get_name(PURPLE_CONVERSATION(im)))) { 194 purple_conversation_get_name(PURPLE_CONVERSATION(im)))) {
140 purple_debug_info("jabber", "Binding conversation to %s\n", 195 purple_debug_info("jabber", "Binding conversation to %s\n",
141 jm->from); 196 jm->from);
142 purple_conversation_set_name(PURPLE_CONVERSATION(im), jm->from); 197 purple_conversation_set_name(PURPLE_CONVERSATION(im), jm->from);
143 } 198 }
154 209
155 g_free(jbr->thread_id); 210 g_free(jbr->thread_id);
156 jbr->thread_id = g_strdup(jbr->thread_id); 211 jbr->thread_id = g_strdup(jbr->thread_id);
157 } 212 }
158 213
159 if (jm->js->googletalk && jm->xhtml == NULL) { 214 purple_serv_got_im(gc, jm->from, body->str, 0, jm->sent);
160 char *tmp = jm->body;
161 jm->body = jabber_google_format_to_html(jm->body);
162 g_free(tmp);
163 }
164 purple_serv_got_im(gc, jm->from, jm->xhtml ? jm->xhtml : jm->body, 0, jm->sent);
165 } 215 }
166 216
167 jabber_id_free(jid); 217 jabber_id_free(jid);
218
219 if(body)
220 g_string_free(body, TRUE);
168 } 221 }
169 222
170 static void handle_headline(JabberMessage *jm) 223 static void handle_headline(JabberMessage *jm)
171 { 224 {
172 char *title; 225 char *title;
173 GString *body; 226 GString *body;
174 GList *etc;
175 227
176 if(!jm->xhtml && !jm->body) 228 if(!jm->xhtml && !jm->body)
177 return; /* ignore headlines without any content */ 229 return; /* ignore headlines without any content */
178 230
179 body = g_string_new(""); 231 body = jm_body_with_oob(jm);
180 title = g_strdup_printf(_("Message from %s"), jm->from); 232 title = g_strdup_printf(_("Message from %s"), jm->from);
181
182 if(jm->xhtml)
183 g_string_append(body, jm->xhtml);
184 else if(jm->body)
185 g_string_append(body, jm->body);
186
187 for(etc = jm->etc; etc; etc = etc->next) {
188 PurpleXmlNode *x = etc->data;
189 const char *xmlns = purple_xmlnode_get_namespace(x);
190 if(xmlns && !strcmp(xmlns, NS_OOB_X_DATA)) {
191 PurpleXmlNode *url, *desc;
192 char *urltxt, *desctxt;
193
194 url = purple_xmlnode_get_child(x, "url");
195 desc = purple_xmlnode_get_child(x, "desc");
196
197 if(!url || !desc)
198 continue;
199
200 urltxt = purple_xmlnode_get_data(url);
201 desctxt = purple_xmlnode_get_data(desc);
202
203 /* I'm all about ugly hacks */
204 if(body->len && jm->body && !strcmp(body->str, jm->body))
205 g_string_printf(body, "<a href='%s'>%s</a>",
206 urltxt, desctxt);
207 else
208 g_string_append_printf(body, "<br/><a href='%s'>%s</a>",
209 urltxt, desctxt);
210
211 g_free(urltxt);
212 g_free(desctxt);
213 }
214 }
215 233
216 purple_notify_formatted(jm->js->gc, title, jm->subject ? jm->subject : title, 234 purple_notify_formatted(jm->js->gc, title, jm->subject ? jm->subject : title,
217 NULL, body->str, NULL, NULL); 235 NULL, body->str, NULL, NULL);
218 236
219 g_free(title); 237 g_free(title);
586 jm->sent = time(NULL); 604 jm->sent = time(NULL);
587 jm->delayed = FALSE; 605 jm->delayed = FALSE;
588 jm->chat_state = JM_STATE_NONE; 606 jm->chat_state = JM_STATE_NONE;
589 607
590 if(type) { 608 if(type) {
591 if(!strcmp(type, "normal")) 609 if(purple_strequal(type, "normal"))
592 jm->type = JABBER_MESSAGE_NORMAL; 610 jm->type = JABBER_MESSAGE_NORMAL;
593 else if(!strcmp(type, "chat")) 611 else if(purple_strequal(type, "chat"))
594 jm->type = JABBER_MESSAGE_CHAT; 612 jm->type = JABBER_MESSAGE_CHAT;
595 else if(!strcmp(type, "groupchat")) 613 else if(purple_strequal(type, "groupchat"))
596 jm->type = JABBER_MESSAGE_GROUPCHAT; 614 jm->type = JABBER_MESSAGE_GROUPCHAT;
597 else if(!strcmp(type, "headline")) 615 else if(purple_strequal(type, "headline"))
598 jm->type = JABBER_MESSAGE_HEADLINE; 616 jm->type = JABBER_MESSAGE_HEADLINE;
599 else if(!strcmp(type, "error")) 617 else if(purple_strequal(type, "error"))
600 jm->type = JABBER_MESSAGE_ERROR; 618 jm->type = JABBER_MESSAGE_ERROR;
601 else 619 else
602 jm->type = JABBER_MESSAGE_OTHER; 620 jm->type = JABBER_MESSAGE_OTHER;
603 } else { 621 } else {
604 jm->type = JABBER_MESSAGE_NORMAL; 622 jm->type = JABBER_MESSAGE_NORMAL;
611 for(child = packet->child; child; child = child->next) { 629 for(child = packet->child; child; child = child->next) {
612 const char *xmlns = purple_xmlnode_get_namespace(child); 630 const char *xmlns = purple_xmlnode_get_namespace(child);
613 if(child->type != PURPLE_XMLNODE_TYPE_TAG) 631 if(child->type != PURPLE_XMLNODE_TYPE_TAG)
614 continue; 632 continue;
615 633
616 if(!strcmp(child->name, "error")) { 634 if(purple_strequal(child->name, "error")) {
617 const char *code = purple_xmlnode_get_attrib(child, "code"); 635 const char *code = purple_xmlnode_get_attrib(child, "code");
618 char *code_txt = NULL; 636 char *code_txt = NULL;
619 char *text = purple_xmlnode_get_data(child); 637 char *text = purple_xmlnode_get_data(child);
620 if (!text) { 638 if (!text) {
621 PurpleXmlNode *enclosed_text_node; 639 PurpleXmlNode *enclosed_text_node;
636 g_free(code_txt); 654 g_free(code_txt);
637 g_free(text); 655 g_free(text);
638 } else if (xmlns == NULL) { 656 } else if (xmlns == NULL) {
639 /* QuLogic: Not certain this is correct, but it would have happened 657 /* QuLogic: Not certain this is correct, but it would have happened
640 with the previous code. */ 658 with the previous code. */
641 if(!strcmp(child->name, "x")) 659 if(purple_strequal(child->name, "x"))
642 jm->etc = g_list_append(jm->etc, child); 660 jm->etc = g_list_append(jm->etc, child);
643 /* The following tests expect xmlns != NULL */ 661 /* The following tests expect xmlns != NULL */
644 continue; 662 continue;
645 } else if(!strcmp(child->name, "subject") && !strcmp(xmlns, NS_XMPP_CLIENT)) { 663 } else if(purple_strequal(child->name, "subject") && purple_strequal(xmlns, NS_XMPP_CLIENT)) {
646 if(!jm->subject) { 664 if(!jm->subject) {
647 jm->subject = purple_xmlnode_get_data(child); 665 jm->subject = purple_xmlnode_get_data(child);
648 if(!jm->subject) 666 if(!jm->subject)
649 jm->subject = g_strdup(""); 667 jm->subject = g_strdup("");
650 } 668 }
651 } else if(!strcmp(child->name, "thread") && !strcmp(xmlns, NS_XMPP_CLIENT)) { 669 } else if(purple_strequal(child->name, "thread") && purple_strequal(xmlns, NS_XMPP_CLIENT)) {
652 if(!jm->thread_id) 670 if(!jm->thread_id)
653 jm->thread_id = purple_xmlnode_get_data(child); 671 jm->thread_id = purple_xmlnode_get_data(child);
654 } else if(!strcmp(child->name, "body") && !strcmp(xmlns, NS_XMPP_CLIENT)) { 672 } else if(purple_strequal(child->name, "body") && purple_strequal(xmlns, NS_XMPP_CLIENT)) {
655 if(!jm->body) { 673 if(!jm->body) {
656 char *msg = purple_xmlnode_get_data(child); 674 char *msg = purple_xmlnode_get_data(child);
657 char *escaped = purple_markup_escape_text(msg, -1); 675 char *escaped = purple_markup_escape_text(msg, -1);
658 jm->body = purple_strdup_withhtml(escaped); 676 jm->body = purple_strdup_withhtml(escaped);
659 g_free(escaped); 677 g_free(escaped);
660 g_free(msg); 678 g_free(msg);
661 } 679 }
662 } else if(!strcmp(child->name, "html") && !strcmp(xmlns, NS_XHTML_IM)) { 680 } else if(purple_strequal(child->name, "html") && purple_strequal(xmlns, NS_XHTML_IM)) {
663 if(!jm->xhtml && purple_xmlnode_get_child(child, "body")) { 681 if(!jm->xhtml && purple_xmlnode_get_child(child, "body")) {
664 char *c; 682 char *c;
665 683
666 const PurpleConnection *gc = js->gc; 684 const PurpleConnection *gc = js->gc;
667 PurpleAccount *account = purple_connection_get_account(gc); 685 PurpleAccount *account = purple_connection_get_account(gc);
738 for (c = jm->xhtml; *c != '\0'; c++) { 756 for (c = jm->xhtml; *c != '\0'; c++) {
739 if (*c == '\n') 757 if (*c == '\n')
740 *c = ' '; 758 *c = ' ';
741 } 759 }
742 } 760 }
743 } else if(!strcmp(child->name, "active") && !strcmp(xmlns,"http://jabber.org/protocol/chatstates")) { 761 } else if(purple_strequal(child->name, "active") && purple_strequal(xmlns,"http://jabber.org/protocol/chatstates")) {
744 jm->chat_state = JM_STATE_ACTIVE; 762 jm->chat_state = JM_STATE_ACTIVE;
745 } else if(!strcmp(child->name, "composing") && !strcmp(xmlns,"http://jabber.org/protocol/chatstates")) { 763 } else if(purple_strequal(child->name, "composing") && purple_strequal(xmlns,"http://jabber.org/protocol/chatstates")) {
746 jm->chat_state = JM_STATE_COMPOSING; 764 jm->chat_state = JM_STATE_COMPOSING;
747 } else if(!strcmp(child->name, "paused") && !strcmp(xmlns,"http://jabber.org/protocol/chatstates")) { 765 } else if(purple_strequal(child->name, "paused") && purple_strequal(xmlns,"http://jabber.org/protocol/chatstates")) {
748 jm->chat_state = JM_STATE_PAUSED; 766 jm->chat_state = JM_STATE_PAUSED;
749 } else if(!strcmp(child->name, "inactive") && !strcmp(xmlns,"http://jabber.org/protocol/chatstates")) { 767 } else if(purple_strequal(child->name, "inactive") && purple_strequal(xmlns,"http://jabber.org/protocol/chatstates")) {
750 jm->chat_state = JM_STATE_INACTIVE; 768 jm->chat_state = JM_STATE_INACTIVE;
751 } else if(!strcmp(child->name, "gone") && !strcmp(xmlns,"http://jabber.org/protocol/chatstates")) { 769 } else if(purple_strequal(child->name, "gone") && purple_strequal(xmlns,"http://jabber.org/protocol/chatstates")) {
752 jm->chat_state = JM_STATE_GONE; 770 jm->chat_state = JM_STATE_GONE;
753 } else if(!strcmp(child->name, "event") && !strcmp(xmlns,"http://jabber.org/protocol/pubsub#event")) { 771 } else if(purple_strequal(child->name, "event") && purple_strequal(xmlns,"http://jabber.org/protocol/pubsub#event")) {
754 PurpleXmlNode *items; 772 PurpleXmlNode *items;
755 jm->type = JABBER_MESSAGE_EVENT; 773 jm->type = JABBER_MESSAGE_EVENT;
756 for(items = purple_xmlnode_get_child(child,"items"); items; items = items->next) 774 for(items = purple_xmlnode_get_child(child,"items"); items; items = items->next)
757 jm->eventitems = g_list_append(jm->eventitems, items); 775 jm->eventitems = g_list_append(jm->eventitems, items);
758 } else if(!strcmp(child->name, "attention") && !strcmp(xmlns, NS_ATTENTION)) { 776 } else if(purple_strequal(child->name, "attention") && purple_strequal(xmlns, NS_ATTENTION)) {
759 jm->hasBuzz = TRUE; 777 jm->hasBuzz = TRUE;
760 } else if(!strcmp(child->name, "delay") && !strcmp(xmlns, NS_DELAYED_DELIVERY)) { 778 } else if(purple_strequal(child->name, "delay") && purple_strequal(xmlns, NS_DELAYED_DELIVERY)) {
761 const char *timestamp = purple_xmlnode_get_attrib(child, "stamp"); 779 const char *timestamp = purple_xmlnode_get_attrib(child, "stamp");
762 jm->delayed = TRUE; 780 jm->delayed = TRUE;
763 if(timestamp) 781 if(timestamp)
764 jm->sent = purple_str_to_time(timestamp, TRUE, NULL, NULL, NULL); 782 jm->sent = purple_str_to_time(timestamp, TRUE, NULL, NULL, NULL);
765 } else if(!strcmp(child->name, "x")) { 783 } else if(purple_strequal(child->name, "x")) {
766 if(!strcmp(xmlns, NS_DELAYED_DELIVERY_LEGACY)) { 784 if(purple_strequal(xmlns, NS_DELAYED_DELIVERY_LEGACY)) {
767 const char *timestamp = purple_xmlnode_get_attrib(child, "stamp"); 785 const char *timestamp = purple_xmlnode_get_attrib(child, "stamp");
768 jm->delayed = TRUE; 786 jm->delayed = TRUE;
769 if(timestamp) 787 if(timestamp)
770 jm->sent = purple_str_to_time(timestamp, TRUE, NULL, NULL, NULL); 788 jm->sent = purple_str_to_time(timestamp, TRUE, NULL, NULL, NULL);
771 } else if(!strcmp(xmlns, "jabber:x:conference") && 789 } else if(purple_strequal(xmlns, "jabber:x:conference") &&
772 jm->type != JABBER_MESSAGE_GROUPCHAT_INVITE && 790 jm->type != JABBER_MESSAGE_GROUPCHAT_INVITE &&
773 jm->type != JABBER_MESSAGE_ERROR) { 791 jm->type != JABBER_MESSAGE_ERROR) {
774 const char *jid = purple_xmlnode_get_attrib(child, "jid"); 792 const char *jid = purple_xmlnode_get_attrib(child, "jid");
775 if(jid) { 793 if(jid) {
776 const char *reason = purple_xmlnode_get_attrib(child, "reason"); 794 const char *reason = purple_xmlnode_get_attrib(child, "reason");
788 if (password) { 806 if (password) {
789 g_free(jm->password); 807 g_free(jm->password);
790 jm->password = g_strdup(password); 808 jm->password = g_strdup(password);
791 } 809 }
792 } 810 }
793 } else if(!strcmp(xmlns, "http://jabber.org/protocol/muc#user") && 811 } else if(purple_strequal(xmlns, "http://jabber.org/protocol/muc#user") &&
794 jm->type != JABBER_MESSAGE_ERROR) { 812 jm->type != JABBER_MESSAGE_ERROR) {
795 PurpleXmlNode *invite = purple_xmlnode_get_child(child, "invite"); 813 PurpleXmlNode *invite = purple_xmlnode_get_child(child, "invite");
796 if(invite) { 814 if(invite) {
797 PurpleXmlNode *reason, *password; 815 PurpleXmlNode *reason, *password;
798 const char *jid = purple_xmlnode_get_attrib(invite, "from"); 816 const char *jid = purple_xmlnode_get_attrib(invite, "from");
811 jm->type = JABBER_MESSAGE_GROUPCHAT_INVITE; 829 jm->type = JABBER_MESSAGE_GROUPCHAT_INVITE;
812 } 830 }
813 } else { 831 } else {
814 jm->etc = g_list_append(jm->etc, child); 832 jm->etc = g_list_append(jm->etc, child);
815 } 833 }
816 } else if (g_str_equal(child->name, "query")) { 834 } else if (purple_strequal(child->name, "query")) {
817 const char *node = purple_xmlnode_get_attrib(child, "node"); 835 const char *node = purple_xmlnode_get_attrib(child, "node");
818 if (purple_strequal(xmlns, NS_DISCO_ITEMS) 836 if (purple_strequal(xmlns, NS_DISCO_ITEMS)
819 && purple_strequal(node, "http://jabber.org/protocol/commands")) { 837 && purple_strequal(node, "http://jabber.org/protocol/commands")) {
820 jabber_adhoc_got_list(js, jm->from, child); 838 jabber_adhoc_got_list(js, jm->from, child);
821 } 839 }

mercurial