Mercurial > pidgin
annotate src/protocols/jabber/message.c @ 7971:6fca0d9cc98b
[gaim-migrate @ 8648]
this particular work of art is topic changing support for jabber, and
support for setting the topic by just changing the text in the chat window.
hopefully someone less lazy than I will implement the right function for
IRC, and any other chats that do topics.
committer: Tailor Script <tailor@pidgin.im>
author | Nathan Walp <nwalp@pidgin.im> |
---|---|
date | Fri, 02 Jan 2004 06:16:44 +0000 |
parents | 64e94b6823c3 |
children | ac01b7d67ff9 |
rev | line source |
---|---|
7014 | 1 /* |
2 * gaim - Jabber Protocol Plugin | |
3 * | |
4 * Copyright (C) 2003, Nathan Walp <faceprint@faceprint.com> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 */ | |
21 #include "internal.h" | |
22 | |
23 #include "debug.h" | |
24 #include "notify.h" | |
25 #include "server.h" | |
7095
c8bf2da398e3
[gaim-migrate @ 7660]
Christian Hammond <chipx86@chipx86.com>
parents:
7014
diff
changeset
|
26 #include "util.h" |
7014 | 27 |
28 #include "buddy.h" | |
29 #include "chat.h" | |
30 #include "message.h" | |
31 #include "xmlnode.h" | |
32 | |
33 #define JABBER_TYPING_NOTIFY_INT 15 | |
34 | |
35 void jabber_message_free(JabberMessage *jm) | |
36 { | |
37 if(jm->from) | |
38 g_free(jm->from); | |
39 if(jm->to) | |
40 g_free(jm->to); | |
41 if(jm->subject) | |
42 g_free(jm->subject); | |
43 if(jm->body) | |
44 g_free(jm->body); | |
45 if(jm->xhtml) | |
46 g_free(jm->xhtml); | |
47 if(jm->password) | |
48 g_free(jm->password); | |
7145 | 49 if(jm->etc) |
50 g_list_free(jm->etc); | |
7014 | 51 |
52 g_free(jm); | |
53 } | |
54 | |
7261 | 55 static GaimConversation * |
7318 | 56 find_unnormalized_im(const char *name, GaimAccount *account) |
7261 | 57 { |
58 GaimConversation *c = NULL; | |
59 GList *cnv; | |
60 | |
61 g_return_val_if_fail(name != NULL, NULL); | |
62 | |
63 for(cnv = gaim_get_conversations(); cnv; cnv = cnv->next) { | |
64 c = (GaimConversation*)cnv->data; | |
7318 | 65 if(gaim_conversation_get_type(c) == GAIM_CONV_IM && |
66 !gaim_utf8_strcasecmp(name, gaim_conversation_get_name(c)) && | |
7261 | 67 account == gaim_conversation_get_account(c)) |
68 return c; | |
69 } | |
70 | |
71 return NULL; | |
72 } | |
73 | |
7145 | 74 static void handle_chat(JabberMessage *jm) |
7014 | 75 { |
76 JabberID *jid = jabber_id_new(jm->from); | |
77 char *from; | |
78 | |
79 JabberBuddy *jb; | |
80 JabberBuddyResource *jbr; | |
81 | |
7310 | 82 if(!jid) |
83 return; | |
84 | |
7014 | 85 jb = jabber_buddy_find(jm->js, jm->from, TRUE); |
7306 | 86 jbr = jabber_buddy_find_resource(jb, jid->resource); |
7014 | 87 |
7318 | 88 if(find_unnormalized_im(jm->from, jm->js->gc->account)) { |
7014 | 89 from = g_strdup(jm->from); |
7258 | 90 } else if(jid->node) { |
91 GaimConversation *conv; | |
92 | |
7014 | 93 from = g_strdup_printf("%s@%s", jid->node, jid->domain); |
7318 | 94 conv = find_unnormalized_im(from, jm->js->gc->account); |
7258 | 95 if(conv) |
96 gaim_conversation_set_name(conv, jm->from); | |
97 g_free(from); | |
98 from = g_strdup(jm->from); | |
99 } else { | |
7014 | 100 from = g_strdup(jid->domain); |
7258 | 101 } |
7014 | 102 |
103 if(!jm->xhtml && !jm->body) { | |
104 if(jm->events & JABBER_MESSAGE_EVENT_COMPOSING) | |
105 serv_got_typing(jm->js->gc, from, 0, GAIM_TYPING); | |
106 else | |
107 serv_got_typing_stopped(jm->js->gc, from); | |
108 } else { | |
109 if(jbr && jm->events & JABBER_MESSAGE_EVENT_COMPOSING) | |
110 jbr->capabilities |= JABBER_CAP_COMPOSING; | |
111 serv_got_im(jm->js->gc, from, jm->xhtml ? jm->xhtml : jm->body, 0, | |
112 jm->sent); | |
113 } | |
114 | |
115 g_free(from); | |
116 jabber_id_free(jid); | |
117 } | |
118 | |
7145 | 119 static void handle_headline(JabberMessage *jm) |
120 { | |
121 char *title; | |
122 GString *body = g_string_new(""); | |
123 GList *etc; | |
124 | |
125 title = g_strdup_printf(_("Message from %s"), jm->from); | |
126 | |
127 if(jm->xhtml) | |
128 g_string_append(body, jm->xhtml); | |
129 else if(jm->body) | |
130 g_string_append(body, jm->body); | |
131 | |
132 for(etc = jm->etc; etc; etc = etc->next) { | |
133 xmlnode *x = etc->data; | |
134 const char *xmlns = xmlnode_get_attrib(x, "xmlns"); | |
135 if(xmlns && !strcmp(xmlns, "jabber:x:oob")) { | |
136 xmlnode *url, *desc; | |
137 char *urltxt, *desctxt; | |
138 | |
139 url = xmlnode_get_child(x, "url"); | |
140 desc = xmlnode_get_child(x, "desc"); | |
141 | |
142 if(!url || !desc) | |
143 continue; | |
144 | |
145 urltxt = xmlnode_get_data(url); | |
146 desctxt = xmlnode_get_data(desc); | |
147 | |
148 /* I'm all about ugly hacks */ | |
149 if(body->len && !strcmp(body->str, jm->body)) | |
150 g_string_printf(body, "<a href='%s'>%s</a>", | |
151 urltxt, desctxt); | |
152 else | |
153 g_string_append_printf(body, "<br/><a href='%s'>%s</a>", | |
154 urltxt, desctxt); | |
155 | |
156 g_free(urltxt); | |
157 g_free(desctxt); | |
158 } | |
159 } | |
160 | |
161 gaim_notify_formatted(jm->js->gc, title, jm->subject ? jm->subject : title, | |
162 NULL, body->str, NULL, NULL); | |
163 | |
164 g_free(title); | |
165 g_string_free(body, TRUE); | |
166 } | |
167 | |
168 static void handle_groupchat(JabberMessage *jm) | |
7014 | 169 { |
170 JabberID *jid = jabber_id_new(jm->from); | |
7310 | 171 JabberChat *chat; |
172 | |
173 if(!jid) | |
174 return; | |
175 | |
176 chat = jabber_chat_find(jm->js, jid->node, jid->domain); | |
7014 | 177 |
178 if(!chat) | |
179 return; | |
180 | |
7971 | 181 if(jm->subject) { |
7183 | 182 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(chat->conv), jid->resource, |
183 jm->subject); | |
7971 | 184 if(!jm->xhtml && !jm->body) { |
185 char *msg; | |
186 if(jid->resource) | |
187 msg = g_strdup_printf(_("%s has set the topic to: %s"), jid->resource, jm->subject); | |
188 else | |
189 msg = g_strdup_printf(_("The topic is: %s"), jm->subject); | |
190 gaim_conv_chat_write(GAIM_CONV_CHAT(chat->conv), "", msg, GAIM_MESSAGE_SYSTEM, jm->sent); | |
191 g_free(msg); | |
192 } | |
193 } | |
7014 | 194 |
7630 | 195 if(jm->xhtml || jm->body) { |
196 if(jid->resource) | |
197 serv_got_chat_in(jm->js->gc, chat->id, jid->resource, 0, | |
198 jm->xhtml ? jm->xhtml : jm->body, jm->sent); | |
199 else if(chat->muc) | |
200 gaim_conv_chat_write(GAIM_CONV_CHAT(chat->conv), "", | |
201 jm->xhtml ? jm->xhtml : jm->body, | |
202 GAIM_MESSAGE_SYSTEM, jm->sent); | |
203 } | |
204 | |
7014 | 205 jabber_id_free(jid); |
206 } | |
207 | |
7145 | 208 static void handle_groupchat_invite(JabberMessage *jm) |
7014 | 209 { |
7310 | 210 GHashTable *components; |
7014 | 211 JabberID *jid = jabber_id_new(jm->to); |
212 | |
7310 | 213 if(!jid) |
214 return; | |
215 | |
216 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); | |
217 | |
7332 | 218 g_hash_table_replace(components, g_strdup("room"), g_strdup(jid->node)); |
7448 | 219 g_hash_table_replace(components, g_strdup("server"), g_strdup(jid->domain)); |
7332 | 220 g_hash_table_replace(components, g_strdup("handle"), |
221 g_strdup(jm->js->user->node)); | |
222 g_hash_table_replace(components, g_strdup("password"), | |
223 g_strdup(jm->password)); | |
7014 | 224 |
225 jabber_id_free(jid); | |
226 serv_got_chat_invite(jm->js->gc, jm->to, jm->from, jm->body, components); | |
227 } | |
228 | |
7145 | 229 static void handle_error(JabberMessage *jm) |
7014 | 230 { |
231 char *buf; | |
232 | |
233 if(!jm->body) | |
234 return; | |
235 | |
236 buf = g_strdup_printf(_("Message delivery to %s failed: %s"), | |
237 jm->from, jm->error); | |
238 | |
7944 | 239 gaim_notify_formatted(jm->js->gc, _("Jabber Message Error"), _("Jabber Message Error"), buf, |
240 jm->xhtml ? jm->xhtml : jm->body, NULL, NULL); | |
7014 | 241 |
242 g_free(buf); | |
243 } | |
244 | |
245 void jabber_message_parse(JabberStream *js, xmlnode *packet) | |
246 { | |
247 JabberMessage *jm; | |
248 const char *type; | |
249 xmlnode *child; | |
250 | |
251 if(strcmp(packet->name, "message")) | |
252 return; | |
253 | |
254 jm = g_new0(JabberMessage, 1); | |
255 jm->js = js; | |
256 jm->sent = time(NULL); | |
257 | |
258 type = xmlnode_get_attrib(packet, "type"); | |
259 | |
260 if(type) { | |
261 if(!strcmp(type, "normal")) | |
262 jm->type = JABBER_MESSAGE_NORMAL; | |
263 else if(!strcmp(type, "chat")) | |
264 jm->type = JABBER_MESSAGE_CHAT; | |
265 else if(!strcmp(type, "groupchat")) | |
266 jm->type = JABBER_MESSAGE_GROUPCHAT; | |
267 else if(!strcmp(type, "headline")) | |
268 jm->type = JABBER_MESSAGE_HEADLINE; | |
269 else if(!strcmp(type, "error")) | |
270 jm->type = JABBER_MESSAGE_ERROR; | |
271 else | |
272 jm->type = JABBER_MESSAGE_OTHER; | |
273 } else { | |
274 jm->type = JABBER_MESSAGE_NORMAL; | |
275 } | |
276 | |
277 jm->from = g_strdup(xmlnode_get_attrib(packet, "from")); | |
278 jm->to = g_strdup(xmlnode_get_attrib(packet, "to")); | |
279 | |
280 for(child = packet->child; child; child = child->next) { | |
281 if(child->type != NODE_TYPE_TAG) | |
282 continue; | |
283 | |
284 if(!strcmp(child->name, "subject")) { | |
285 if(!jm->subject) | |
286 jm->subject = xmlnode_get_data(child); | |
287 } else if(!strcmp(child->name, "body")) { | |
288 if(!jm->body) | |
7894 | 289 jm->body = xmlnode_to_str(child, NULL); |
7241 | 290 } else if(!strcmp(child->name, "html")) { |
291 if(!jm->xhtml) | |
7642 | 292 jm->xhtml = xmlnode_to_str(child, NULL); |
7014 | 293 } else if(!strcmp(child->name, "error")) { |
294 const char *code = xmlnode_get_attrib(child, "code"); | |
295 char *code_txt = NULL; | |
296 char *text = xmlnode_get_data(child); | |
297 | |
298 if(code) | |
299 code_txt = g_strdup_printf(_(" (Code %s)"), code); | |
300 | |
301 if(!jm->error) | |
302 jm->error = g_strdup_printf("%s%s", text ? text : "", | |
303 code_txt ? code_txt : ""); | |
304 | |
305 g_free(code_txt); | |
306 g_free(text); | |
307 } else if(!strcmp(child->name, "x")) { | |
308 const char *xmlns = xmlnode_get_attrib(child, "xmlns"); | |
309 if(xmlns && !strcmp(xmlns, "jabber:x:event")) { | |
310 if(xmlnode_get_child(child, "composing")) | |
311 jm->events |= JABBER_MESSAGE_EVENT_COMPOSING; | |
312 } else if(xmlns && !strcmp(xmlns, "jabber:x:delay")) { | |
313 const char *timestamp = xmlnode_get_attrib(child, "stamp"); | |
314 if(timestamp) | |
315 jm->sent = str_to_time(timestamp); | |
316 } else if(xmlns && !strcmp(xmlns, "jabber:x:conference") && | |
317 jm->type != JABBER_MESSAGE_GROUPCHAT_INVITE) { | |
318 const char *jid = xmlnode_get_attrib(child, "jid"); | |
319 if(jid) { | |
320 jm->type = JABBER_MESSAGE_GROUPCHAT_INVITE; | |
321 g_free(jm->to); | |
322 jm->to = g_strdup(jid); | |
323 } | |
324 } else if(xmlns && !strcmp(xmlns, | |
325 "http://jabber.org/protocol/muc#user")) { | |
326 xmlnode *invite = xmlnode_get_child(child, "invite"); | |
327 if(invite) { | |
328 xmlnode *reason, *password; | |
7968 | 329 const char *jid = xmlnode_get_attrib(invite, "from"); |
7014 | 330 g_free(jm->to); |
331 jm->to = jm->from; | |
332 jm->from = g_strdup(jid); | |
333 if((reason = xmlnode_get_child(invite, "reason"))) { | |
334 g_free(jm->body); | |
335 jm->body = xmlnode_get_data(reason); | |
336 } | |
337 if((password = xmlnode_get_child(invite, "password"))) | |
338 jm->password = xmlnode_get_data(password); | |
339 | |
340 jm->type = JABBER_MESSAGE_GROUPCHAT_INVITE; | |
341 } | |
7145 | 342 } else { |
343 jm->etc = g_list_append(jm->etc, child); | |
7014 | 344 } |
345 } | |
346 } | |
347 | |
348 switch(jm->type) { | |
349 case JABBER_MESSAGE_NORMAL: | |
350 case JABBER_MESSAGE_CHAT: | |
7145 | 351 handle_chat(jm); |
352 break; | |
7014 | 353 case JABBER_MESSAGE_HEADLINE: |
7145 | 354 handle_headline(jm); |
7014 | 355 break; |
356 case JABBER_MESSAGE_GROUPCHAT: | |
357 handle_groupchat(jm); | |
358 break; | |
359 case JABBER_MESSAGE_GROUPCHAT_INVITE: | |
360 handle_groupchat_invite(jm); | |
361 break; | |
362 case JABBER_MESSAGE_ERROR: | |
363 handle_error(jm); | |
364 break; | |
365 case JABBER_MESSAGE_OTHER: | |
366 gaim_debug(GAIM_DEBUG_INFO, "jabber", | |
367 "Received message of unknown type: %s\n", type); | |
368 break; | |
369 } | |
370 jabber_message_free(jm); | |
371 } | |
372 | |
373 void jabber_message_send(JabberMessage *jm) | |
374 { | |
375 xmlnode *message, *child; | |
376 const char *type = NULL; | |
377 | |
378 message = xmlnode_new("message"); | |
379 | |
380 switch(jm->type) { | |
381 case JABBER_MESSAGE_NORMAL: | |
382 type = "normal"; | |
383 break; | |
384 case JABBER_MESSAGE_CHAT: | |
385 case JABBER_MESSAGE_GROUPCHAT_INVITE: | |
386 type = "chat"; | |
387 break; | |
388 case JABBER_MESSAGE_HEADLINE: | |
389 type = "headline"; | |
390 break; | |
391 case JABBER_MESSAGE_GROUPCHAT: | |
392 type = "groupchat"; | |
393 break; | |
394 case JABBER_MESSAGE_ERROR: | |
395 type = "error"; | |
396 break; | |
397 case JABBER_MESSAGE_OTHER: | |
398 type = NULL; | |
399 break; | |
400 } | |
401 | |
402 if(type) | |
403 xmlnode_set_attrib(message, "type", type); | |
404 | |
405 xmlnode_set_attrib(message, "to", jm->to); | |
406 | |
7971 | 407 if(jm->events || (!jm->body && !jm->xhtml && !jm->subject)) { |
7014 | 408 child = xmlnode_new_child(message, "x"); |
409 xmlnode_set_attrib(child, "xmlns", "jabber:x:event"); | |
410 if(jm->events & JABBER_MESSAGE_EVENT_COMPOSING) | |
411 xmlnode_new_child(child, "composing"); | |
412 } | |
413 | |
414 if(jm->subject) { | |
415 child = xmlnode_new_child(message, "subject"); | |
416 xmlnode_insert_data(child, jm->subject, -1); | |
417 } | |
418 | |
419 if(jm->body) { | |
420 child = xmlnode_new_child(message, "body"); | |
421 xmlnode_insert_data(child, jm->body, -1); | |
422 } | |
423 | |
424 if(jm->xhtml) { | |
425 child = xmlnode_from_str(jm->xhtml, -1); | |
426 if(child) { | |
427 xmlnode_insert_child(message, child); | |
428 } else { | |
429 gaim_debug(GAIM_DEBUG_ERROR, "jabber", | |
430 "XHTML translation/validation failed, returning: %s\n", | |
431 jm->xhtml); | |
432 } | |
433 } | |
434 | |
435 jabber_send(jm->js, message); | |
436 | |
437 xmlnode_free(message); | |
438 } | |
439 | |
440 int jabber_message_send_im(GaimConnection *gc, const char *who, const char *msg, | |
7118
bf630f7dfdcd
[gaim-migrate @ 7685]
Christian Hammond <chipx86@chipx86.com>
parents:
7095
diff
changeset
|
441 GaimConvImFlags flags) |
7014 | 442 { |
443 JabberMessage *jm; | |
444 JabberBuddy *jb; | |
445 JabberBuddyResource *jbr; | |
446 char *buf; | |
7135 | 447 char *xhtml; |
7306 | 448 char *resource; |
7014 | 449 |
450 if(!who || !msg) | |
451 return 0; | |
452 | |
7306 | 453 resource = jabber_get_resource(who); |
454 | |
7014 | 455 jb = jabber_buddy_find(gc->proto_data, who, TRUE); |
7306 | 456 jbr = jabber_buddy_find_resource(jb, resource); |
457 | |
458 g_free(resource); | |
7014 | 459 |
460 jm = g_new0(JabberMessage, 1); | |
461 jm->js = gc->proto_data; | |
462 jm->type = JABBER_MESSAGE_CHAT; | |
463 jm->events = JABBER_MESSAGE_EVENT_COMPOSING; | |
464 jm->to = g_strdup(who); | |
465 | |
7773 | 466 buf = g_strdup_printf("<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html>", msg); |
7014 | 467 |
7135 | 468 gaim_markup_html_to_xhtml(buf, &xhtml, &jm->body); |
7014 | 469 g_free(buf); |
470 | |
471 if(!jbr || jbr->capabilities & JABBER_CAP_XHTML) | |
472 jm->xhtml = xhtml; | |
473 else | |
474 g_free(xhtml); | |
475 | |
476 jabber_message_send(jm); | |
477 jabber_message_free(jm); | |
478 return 1; | |
479 } | |
480 | |
7345 | 481 int jabber_message_send_chat(GaimConnection *gc, int id, const char *msg) |
7014 | 482 { |
483 JabberChat *chat; | |
484 JabberMessage *jm; | |
485 JabberStream *js = gc->proto_data; | |
7345 | 486 char *buf, *xhtml; |
7014 | 487 |
7345 | 488 if(!msg) |
7014 | 489 return 0; |
490 | |
491 chat = jabber_chat_find_by_id(js, id); | |
492 | |
7923 | 493 if(!strcmp(msg, "/configure") || !strcmp(msg, "/config")) { |
494 jabber_chat_request_room_configure(chat); | |
495 return 1; | |
7955 | 496 } else if(!strcmp(msg, "/register")) { |
497 jabber_chat_register(chat); | |
7971 | 498 return 1; |
499 } else if(!strncmp(msg, "/topic", 6)) { | |
500 jabber_chat_change_topic(chat, strlen(msg) > 7 ? msg+7 : NULL); | |
501 return 1; | |
7923 | 502 } |
503 | |
7014 | 504 jm = g_new0(JabberMessage, 1); |
505 jm->js = gc->proto_data; | |
7444 | 506 jm->type = JABBER_MESSAGE_GROUPCHAT; |
7014 | 507 jm->to = g_strdup_printf("%s@%s", chat->room, chat->server); |
508 | |
7773 | 509 buf = g_strdup_printf("<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html>", msg); |
7345 | 510 |
511 gaim_markup_html_to_xhtml(buf, &xhtml, &jm->body); | |
512 g_free(buf); | |
513 | |
514 if(chat->xhtml) | |
515 jm->xhtml = xhtml; | |
516 else | |
517 g_free(xhtml); | |
7014 | 518 |
519 jabber_message_send(jm); | |
520 jabber_message_free(jm); | |
521 return 1; | |
522 } | |
523 | |
524 int jabber_send_typing(GaimConnection *gc, const char *who, int typing) | |
525 { | |
526 JabberMessage *jm; | |
527 JabberBuddy *jb; | |
528 JabberBuddyResource *jbr; | |
7306 | 529 char *resource = jabber_get_resource(who); |
7014 | 530 |
531 jb = jabber_buddy_find(gc->proto_data, who, TRUE); | |
7306 | 532 jbr = jabber_buddy_find_resource(jb, resource); |
533 | |
534 g_free(resource); | |
7014 | 535 |
7187 | 536 if(!jbr || !(jbr->capabilities & JABBER_CAP_COMPOSING)) |
7014 | 537 return 0; |
538 | |
539 jm = g_new0(JabberMessage, 1); | |
540 jm->js = gc->proto_data; | |
541 jm->type = JABBER_MESSAGE_CHAT; | |
542 jm->to = g_strdup(who); | |
543 | |
544 if(typing == GAIM_TYPING) | |
545 jm->events = JABBER_MESSAGE_EVENT_COMPOSING; | |
546 | |
547 jabber_message_send(jm); | |
548 jabber_message_free(jm); | |
549 | |
550 return JABBER_TYPING_NOTIFY_INT; | |
551 } | |
552 |