| 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 |
| 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; |
| 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"); |
| 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 } |