14192
|
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"
|
|
26 #include "util.h"
|
|
27
|
|
28 #include "buddy.h"
|
|
29 #include "chat.h"
|
|
30 #include "message.h"
|
|
31 #include "xmlnode.h"
|
|
32
|
|
33 void jabber_message_free(JabberMessage *jm)
|
|
34 {
|
|
35 g_free(jm->from);
|
|
36 g_free(jm->to);
|
|
37 g_free(jm->id);
|
|
38 g_free(jm->subject);
|
|
39 g_free(jm->body);
|
|
40 g_free(jm->xhtml);
|
|
41 g_free(jm->password);
|
|
42 g_list_free(jm->etc);
|
|
43
|
|
44 g_free(jm);
|
|
45 }
|
|
46
|
|
47 static void handle_chat(JabberMessage *jm)
|
|
48 {
|
|
49 JabberID *jid = jabber_id_new(jm->from);
|
|
50 char *from;
|
|
51
|
|
52 JabberBuddy *jb;
|
|
53 JabberBuddyResource *jbr;
|
|
54
|
|
55 if(!jid)
|
|
56 return;
|
|
57
|
|
58 jb = jabber_buddy_find(jm->js, jm->from, TRUE);
|
|
59 jbr = jabber_buddy_find_resource(jb, jid->resource);
|
|
60
|
|
61 if(jabber_find_unnormalized_conv(jm->from, jm->js->gc->account)) {
|
|
62 from = g_strdup(jm->from);
|
|
63 } else if(jid->node) {
|
|
64 if(jid->resource) {
|
|
65 GaimConversation *conv;
|
|
66
|
|
67 from = g_strdup_printf("%s@%s", jid->node, jid->domain);
|
|
68 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, from, jm->js->gc->account);
|
|
69 if(conv) {
|
|
70 gaim_conversation_set_name(conv, jm->from);
|
|
71 }
|
|
72 g_free(from);
|
|
73 }
|
|
74 from = g_strdup(jm->from);
|
|
75 } else {
|
|
76 from = g_strdup(jid->domain);
|
|
77 }
|
|
78
|
|
79 if(!jm->xhtml && !jm->body) {
|
|
80 if(JM_STATE_COMPOSING == jm->chat_state)
|
|
81 serv_got_typing(jm->js->gc, from, 0, GAIM_TYPING);
|
|
82 else if(JM_STATE_PAUSED == jm->chat_state)
|
|
83 serv_got_typing(jm->js->gc, from, 0, GAIM_TYPED);
|
|
84 else
|
|
85 serv_got_typing_stopped(jm->js->gc, from);
|
|
86 } else {
|
|
87 if(jbr) {
|
|
88 if(JM_TS_JEP_0085 == (jm->typing_style & JM_TS_JEP_0085)) {
|
|
89 jbr->chat_states = JABBER_CHAT_STATES_SUPPORTED;
|
|
90 } else {
|
|
91 jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED;
|
|
92 }
|
|
93
|
|
94 if(JM_TS_JEP_0022 == (jm->typing_style & JM_TS_JEP_0022)) {
|
|
95 jbr->capabilities |= JABBER_CAP_COMPOSING;
|
|
96 }
|
|
97
|
|
98 if(jbr->thread_id)
|
|
99 g_free(jbr->thread_id);
|
|
100 jbr->thread_id = g_strdup(jbr->thread_id);
|
|
101 }
|
|
102 serv_got_im(jm->js->gc, from, jm->xhtml ? jm->xhtml : jm->body, 0,
|
|
103 jm->sent);
|
|
104 }
|
|
105
|
|
106
|
|
107 g_free(from);
|
|
108 jabber_id_free(jid);
|
|
109 }
|
|
110
|
|
111 static void handle_headline(JabberMessage *jm)
|
|
112 {
|
|
113 char *title;
|
|
114 GString *body = g_string_new("");
|
|
115 GList *etc;
|
|
116
|
|
117 title = g_strdup_printf(_("Message from %s"), jm->from);
|
|
118
|
|
119 if(jm->xhtml)
|
|
120 g_string_append(body, jm->xhtml);
|
|
121 else if(jm->body)
|
|
122 g_string_append(body, jm->body);
|
|
123
|
|
124 for(etc = jm->etc; etc; etc = etc->next) {
|
|
125 xmlnode *x = etc->data;
|
|
126 const char *xmlns = xmlnode_get_namespace(x);
|
|
127 if(xmlns && !strcmp(xmlns, "jabber:x:oob")) {
|
|
128 xmlnode *url, *desc;
|
|
129 char *urltxt, *desctxt;
|
|
130
|
|
131 url = xmlnode_get_child(x, "url");
|
|
132 desc = xmlnode_get_child(x, "desc");
|
|
133
|
|
134 if(!url || !desc)
|
|
135 continue;
|
|
136
|
|
137 urltxt = xmlnode_get_data(url);
|
|
138 desctxt = xmlnode_get_data(desc);
|
|
139
|
|
140 /* I'm all about ugly hacks */
|
|
141 if(body->len && !strcmp(body->str, jm->body))
|
|
142 g_string_printf(body, "<a href='%s'>%s</a>",
|
|
143 urltxt, desctxt);
|
|
144 else
|
|
145 g_string_append_printf(body, "<br/><a href='%s'>%s</a>",
|
|
146 urltxt, desctxt);
|
|
147
|
|
148 g_free(urltxt);
|
|
149 g_free(desctxt);
|
|
150 }
|
|
151 }
|
|
152
|
|
153 gaim_notify_formatted(jm->js->gc, title, jm->subject ? jm->subject : title,
|
|
154 NULL, body->str, NULL, NULL);
|
|
155
|
|
156 g_free(title);
|
|
157 g_string_free(body, TRUE);
|
|
158 }
|
|
159
|
|
160 static void handle_groupchat(JabberMessage *jm)
|
|
161 {
|
|
162 JabberID *jid = jabber_id_new(jm->from);
|
|
163 JabberChat *chat;
|
|
164
|
|
165 if(!jid)
|
|
166 return;
|
|
167
|
|
168 chat = jabber_chat_find(jm->js, jid->node, jid->domain);
|
|
169
|
|
170 if(!chat)
|
|
171 return;
|
|
172
|
|
173 if(jm->subject) {
|
|
174 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(chat->conv), jid->resource,
|
|
175 jm->subject);
|
|
176 if(!jm->xhtml && !jm->body) {
|
|
177 char *msg, *tmp, *tmp2;
|
|
178 tmp = g_markup_escape_text(jm->subject, -1);
|
|
179 tmp2 = gaim_markup_linkify(tmp);
|
|
180 if(jid->resource)
|
|
181 msg = g_strdup_printf(_("%s has set the topic to: %s"), jid->resource, tmp2);
|
|
182 else
|
|
183 msg = g_strdup_printf(_("The topic is: %s"), tmp2);
|
|
184 gaim_conv_chat_write(GAIM_CONV_CHAT(chat->conv), "", msg, GAIM_MESSAGE_SYSTEM, jm->sent);
|
|
185 g_free(tmp);
|
|
186 g_free(tmp2);
|
|
187 g_free(msg);
|
|
188 }
|
|
189 }
|
|
190
|
|
191 if(jm->xhtml || jm->body) {
|
|
192 if(jid->resource)
|
|
193 serv_got_chat_in(jm->js->gc, chat->id, jid->resource,
|
|
194 jm->delayed ? GAIM_MESSAGE_DELAYED : 0,
|
|
195 jm->xhtml ? jm->xhtml : jm->body, jm->sent);
|
|
196 else if(chat->muc)
|
|
197 gaim_conv_chat_write(GAIM_CONV_CHAT(chat->conv), "",
|
|
198 jm->xhtml ? jm->xhtml : jm->body,
|
|
199 GAIM_MESSAGE_SYSTEM, jm->sent);
|
|
200 }
|
|
201
|
|
202 jabber_id_free(jid);
|
|
203 }
|
|
204
|
|
205 static void handle_groupchat_invite(JabberMessage *jm)
|
|
206 {
|
|
207 GHashTable *components;
|
|
208 JabberID *jid = jabber_id_new(jm->to);
|
|
209
|
|
210 if(!jid)
|
|
211 return;
|
|
212
|
|
213 components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
|
|
214
|
|
215 g_hash_table_replace(components, g_strdup("room"), g_strdup(jid->node));
|
|
216 g_hash_table_replace(components, g_strdup("server"), g_strdup(jid->domain));
|
|
217 g_hash_table_replace(components, g_strdup("handle"),
|
|
218 g_strdup(jm->js->user->node));
|
|
219 g_hash_table_replace(components, g_strdup("password"),
|
|
220 g_strdup(jm->password));
|
|
221
|
|
222 jabber_id_free(jid);
|
|
223 serv_got_chat_invite(jm->js->gc, jm->to, jm->from, jm->body, components);
|
|
224 }
|
|
225
|
|
226 static void handle_error(JabberMessage *jm)
|
|
227 {
|
|
228 char *buf;
|
|
229
|
|
230 if(!jm->body)
|
|
231 return;
|
|
232
|
|
233 buf = g_strdup_printf(_("Message delivery to %s failed: %s"),
|
|
234 jm->from, jm->error ? jm->error : "");
|
|
235
|
|
236 gaim_notify_formatted(jm->js->gc, _("Jabber Message Error"), _("Jabber Message Error"), buf,
|
|
237 jm->xhtml ? jm->xhtml : jm->body, NULL, NULL);
|
|
238
|
|
239 g_free(buf);
|
|
240 }
|
|
241
|
|
242 void jabber_message_parse(JabberStream *js, xmlnode *packet)
|
|
243 {
|
|
244 JabberMessage *jm;
|
|
245 const char *type;
|
|
246 xmlnode *child;
|
|
247
|
|
248 jm = g_new0(JabberMessage, 1);
|
|
249 jm->js = js;
|
|
250 jm->sent = time(NULL);
|
|
251 jm->delayed = FALSE;
|
|
252
|
|
253 type = xmlnode_get_attrib(packet, "type");
|
|
254
|
|
255 if(type) {
|
|
256 if(!strcmp(type, "normal"))
|
|
257 jm->type = JABBER_MESSAGE_NORMAL;
|
|
258 else if(!strcmp(type, "chat"))
|
|
259 jm->type = JABBER_MESSAGE_CHAT;
|
|
260 else if(!strcmp(type, "groupchat"))
|
|
261 jm->type = JABBER_MESSAGE_GROUPCHAT;
|
|
262 else if(!strcmp(type, "headline"))
|
|
263 jm->type = JABBER_MESSAGE_HEADLINE;
|
|
264 else if(!strcmp(type, "error"))
|
|
265 jm->type = JABBER_MESSAGE_ERROR;
|
|
266 else
|
|
267 jm->type = JABBER_MESSAGE_OTHER;
|
|
268 } else {
|
|
269 jm->type = JABBER_MESSAGE_NORMAL;
|
|
270 }
|
|
271
|
|
272 jm->from = g_strdup(xmlnode_get_attrib(packet, "from"));
|
|
273 jm->to = g_strdup(xmlnode_get_attrib(packet, "to"));
|
|
274 jm->id = g_strdup(xmlnode_get_attrib(packet, "id"));
|
|
275
|
|
276 for(child = packet->child; child; child = child->next) {
|
|
277 if(child->type != XMLNODE_TYPE_TAG)
|
|
278 continue;
|
|
279
|
|
280 if(!strcmp(child->name, "subject")) {
|
|
281 if(!jm->subject)
|
|
282 jm->subject = xmlnode_get_data(child);
|
|
283 } else if(!strcmp(child->name, "thread")) {
|
|
284 if(!jm->thread_id)
|
|
285 jm->thread_id = xmlnode_get_data(child);
|
|
286 } else if(!strcmp(child->name, "body")) {
|
|
287 if(!jm->body) {
|
|
288 char *msg = xmlnode_to_str(child, NULL);
|
|
289 jm->body = gaim_strdup_withhtml(msg);
|
|
290 g_free(msg);
|
|
291 }
|
|
292 } else if(!strcmp(child->name, "html")) {
|
|
293 if(!jm->xhtml && xmlnode_get_child(child, "body"))
|
|
294 jm->xhtml = xmlnode_to_str(child, NULL);
|
|
295 } else if(!strcmp(child->name, "active")) {
|
|
296 jm->chat_state = JM_STATE_ACTIVE;
|
|
297 jm->typing_style |= JM_TS_JEP_0085;
|
|
298 } else if(!strcmp(child->name, "composing")) {
|
|
299 jm->chat_state = JM_STATE_COMPOSING;
|
|
300 jm->typing_style |= JM_TS_JEP_0085;
|
|
301 } else if(!strcmp(child->name, "paused")) {
|
|
302 jm->chat_state = JM_STATE_PAUSED;
|
|
303 jm->typing_style |= JM_TS_JEP_0085;
|
|
304 } else if(!strcmp(child->name, "inactive")) {
|
|
305 jm->chat_state = JM_STATE_INACTIVE;
|
|
306 jm->typing_style |= JM_TS_JEP_0085;
|
|
307 } else if(!strcmp(child->name, "gone")) {
|
|
308 jm->chat_state = JM_STATE_GONE;
|
|
309 jm->typing_style |= JM_TS_JEP_0085;
|
|
310 } else if(!strcmp(child->name, "error")) {
|
|
311 const char *code = xmlnode_get_attrib(child, "code");
|
|
312 char *code_txt = NULL;
|
|
313 char *text = xmlnode_get_data(child);
|
|
314
|
|
315 if(code)
|
|
316 code_txt = g_strdup_printf(_(" (Code %s)"), code);
|
|
317
|
|
318 if(!jm->error)
|
|
319 jm->error = g_strdup_printf("%s%s", text ? text : "",
|
|
320 code_txt ? code_txt : "");
|
|
321
|
|
322 g_free(code_txt);
|
|
323 g_free(text);
|
|
324 } else if(!strcmp(child->name, "x")) {
|
|
325 const char *xmlns = xmlnode_get_namespace(child);
|
|
326 if(xmlns && !strcmp(xmlns, "jabber:x:event")) {
|
|
327 if(xmlnode_get_child(child, "composing")) {
|
|
328 if(jm->chat_state == JM_STATE_ACTIVE)
|
|
329 jm->chat_state = JM_STATE_COMPOSING;
|
|
330 jm->typing_style |= JM_TS_JEP_0022;
|
|
331 }
|
|
332 } else if(xmlns && !strcmp(xmlns, "jabber:x:delay")) {
|
|
333 const char *timestamp = xmlnode_get_attrib(child, "stamp");
|
|
334 jm->delayed = TRUE;
|
|
335 if(timestamp)
|
|
336 jm->sent = gaim_str_to_time(timestamp, TRUE, NULL, NULL, NULL);
|
|
337 } else if(xmlns && !strcmp(xmlns, "jabber:x:conference") &&
|
|
338 jm->type != JABBER_MESSAGE_GROUPCHAT_INVITE &&
|
|
339 jm->type != JABBER_MESSAGE_ERROR) {
|
|
340 const char *jid = xmlnode_get_attrib(child, "jid");
|
|
341 if(jid) {
|
|
342 jm->type = JABBER_MESSAGE_GROUPCHAT_INVITE;
|
|
343 g_free(jm->to);
|
|
344 jm->to = g_strdup(jid);
|
|
345 }
|
|
346 } else if(xmlns && !strcmp(xmlns,
|
|
347 "http://jabber.org/protocol/muc#user") &&
|
|
348 jm->type != JABBER_MESSAGE_ERROR) {
|
|
349 xmlnode *invite = xmlnode_get_child(child, "invite");
|
|
350 if(invite) {
|
|
351 xmlnode *reason, *password;
|
|
352 const char *jid = xmlnode_get_attrib(invite, "from");
|
|
353 g_free(jm->to);
|
|
354 jm->to = jm->from;
|
|
355 jm->from = g_strdup(jid);
|
|
356 if((reason = xmlnode_get_child(invite, "reason"))) {
|
|
357 g_free(jm->body);
|
|
358 jm->body = xmlnode_get_data(reason);
|
|
359 }
|
|
360 if((password = xmlnode_get_child(child, "password")))
|
|
361 jm->password = xmlnode_get_data(password);
|
|
362
|
|
363 jm->type = JABBER_MESSAGE_GROUPCHAT_INVITE;
|
|
364 }
|
|
365 } else {
|
|
366 jm->etc = g_list_append(jm->etc, child);
|
|
367 }
|
|
368 }
|
|
369 }
|
|
370
|
|
371 switch(jm->type) {
|
|
372 case JABBER_MESSAGE_NORMAL:
|
|
373 case JABBER_MESSAGE_CHAT:
|
|
374 handle_chat(jm);
|
|
375 break;
|
|
376 case JABBER_MESSAGE_HEADLINE:
|
|
377 handle_headline(jm);
|
|
378 break;
|
|
379 case JABBER_MESSAGE_GROUPCHAT:
|
|
380 handle_groupchat(jm);
|
|
381 break;
|
|
382 case JABBER_MESSAGE_GROUPCHAT_INVITE:
|
|
383 handle_groupchat_invite(jm);
|
|
384 break;
|
|
385 case JABBER_MESSAGE_ERROR:
|
|
386 handle_error(jm);
|
|
387 break;
|
|
388 case JABBER_MESSAGE_OTHER:
|
|
389 gaim_debug(GAIM_DEBUG_INFO, "jabber",
|
|
390 "Received message of unknown type: %s\n", type);
|
|
391 break;
|
|
392 }
|
|
393 jabber_message_free(jm);
|
|
394 }
|
|
395
|
|
396 void jabber_message_send(JabberMessage *jm)
|
|
397 {
|
|
398 xmlnode *message, *child;
|
|
399 const char *type = NULL;
|
|
400
|
|
401 message = xmlnode_new("message");
|
|
402
|
|
403 switch(jm->type) {
|
|
404 case JABBER_MESSAGE_NORMAL:
|
|
405 type = "normal";
|
|
406 break;
|
|
407 case JABBER_MESSAGE_CHAT:
|
|
408 case JABBER_MESSAGE_GROUPCHAT_INVITE:
|
|
409 type = "chat";
|
|
410 break;
|
|
411 case JABBER_MESSAGE_HEADLINE:
|
|
412 type = "headline";
|
|
413 break;
|
|
414 case JABBER_MESSAGE_GROUPCHAT:
|
|
415 type = "groupchat";
|
|
416 break;
|
|
417 case JABBER_MESSAGE_ERROR:
|
|
418 type = "error";
|
|
419 break;
|
|
420 case JABBER_MESSAGE_OTHER:
|
|
421 type = NULL;
|
|
422 break;
|
|
423 }
|
|
424
|
|
425 if(type)
|
|
426 xmlnode_set_attrib(message, "type", type);
|
|
427
|
|
428 if (jm->id)
|
|
429 xmlnode_set_attrib(message, "id", jm->id);
|
|
430
|
|
431 xmlnode_set_attrib(message, "to", jm->to);
|
|
432
|
|
433 if(jm->thread_id) {
|
|
434 child = xmlnode_new_child(message, "thread");
|
|
435 xmlnode_insert_data(child, jm->thread_id, -1);
|
|
436 }
|
|
437
|
|
438 if(JM_TS_JEP_0022 == (jm->typing_style & JM_TS_JEP_0022)) {
|
|
439 child = xmlnode_new_child(message, "x");
|
|
440 xmlnode_set_namespace(child, "jabber:x:event");
|
|
441 if(jm->chat_state == JM_STATE_COMPOSING || jm->body)
|
|
442 xmlnode_new_child(child, "composing");
|
|
443 }
|
|
444
|
|
445 if(JM_TS_JEP_0085 == (jm->typing_style & JM_TS_JEP_0085)) {
|
|
446 child = NULL;
|
|
447 switch(jm->chat_state)
|
|
448 {
|
|
449 case JM_STATE_ACTIVE:
|
|
450 child = xmlnode_new_child(message, "active");
|
|
451 break;
|
|
452 case JM_STATE_COMPOSING:
|
|
453 child = xmlnode_new_child(message, "composing");
|
|
454 break;
|
|
455 case JM_STATE_PAUSED:
|
|
456 child = xmlnode_new_child(message, "paused");
|
|
457 break;
|
|
458 case JM_STATE_INACTIVE:
|
|
459 child = xmlnode_new_child(message, "inactive");
|
|
460 break;
|
|
461 case JM_STATE_GONE:
|
|
462 child = xmlnode_new_child(message, "gone");
|
|
463 break;
|
|
464 }
|
|
465 if(child)
|
|
466 xmlnode_set_namespace(child, "http://jabber.org/protocol/chatstates");
|
|
467 }
|
|
468
|
|
469 if(jm->subject) {
|
|
470 child = xmlnode_new_child(message, "subject");
|
|
471 xmlnode_insert_data(child, jm->subject, -1);
|
|
472 }
|
|
473
|
|
474 if(jm->body) {
|
|
475 child = xmlnode_new_child(message, "body");
|
|
476 xmlnode_insert_data(child, jm->body, -1);
|
|
477 }
|
|
478
|
|
479 if(jm->xhtml) {
|
|
480 child = xmlnode_from_str(jm->xhtml, -1);
|
|
481 if(child) {
|
|
482 xmlnode_insert_child(message, child);
|
|
483 } else {
|
|
484 gaim_debug(GAIM_DEBUG_ERROR, "jabber",
|
|
485 "XHTML translation/validation failed, returning: %s\n",
|
|
486 jm->xhtml);
|
|
487 }
|
|
488 }
|
|
489
|
|
490 jabber_send(jm->js, message);
|
|
491
|
|
492 xmlnode_free(message);
|
|
493 }
|
|
494
|
|
495 int jabber_message_send_im(GaimConnection *gc, const char *who, const char *msg,
|
|
496 GaimMessageFlags flags)
|
|
497 {
|
|
498 JabberMessage *jm;
|
|
499 JabberBuddy *jb;
|
|
500 JabberBuddyResource *jbr;
|
|
501 char *buf;
|
|
502 char *xhtml;
|
|
503 char *resource;
|
|
504
|
|
505 if(!who || !msg)
|
|
506 return 0;
|
|
507
|
|
508 resource = jabber_get_resource(who);
|
|
509
|
|
510 jb = jabber_buddy_find(gc->proto_data, who, TRUE);
|
|
511 jbr = jabber_buddy_find_resource(jb, resource);
|
|
512
|
|
513 g_free(resource);
|
|
514
|
|
515 jm = g_new0(JabberMessage, 1);
|
|
516 jm->js = gc->proto_data;
|
|
517 jm->type = JABBER_MESSAGE_CHAT;
|
|
518 jm->chat_state = JM_STATE_ACTIVE;
|
|
519 jm->to = g_strdup(who);
|
|
520 jm->id = jabber_get_next_id(jm->js);
|
|
521 jm->chat_state = JM_STATE_ACTIVE;
|
|
522
|
|
523 if(jbr) {
|
|
524 if(jbr->thread_id)
|
|
525 jm->thread_id = jbr->thread_id;
|
|
526
|
|
527 if(jbr->chat_states != JABBER_CHAT_STATES_UNSUPPORTED) {
|
|
528 jm->typing_style |= JM_TS_JEP_0085;
|
|
529 /* if(JABBER_CHAT_STATES_UNKNOWN == jbr->chat_states)
|
|
530 jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED; */
|
|
531 }
|
|
532
|
|
533 if(jbr->chat_states != JABBER_CHAT_STATES_SUPPORTED)
|
|
534 jm->typing_style |= JM_TS_JEP_0022;
|
|
535 }
|
|
536
|
|
537 buf = g_strdup_printf("<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html>", msg);
|
|
538
|
|
539 gaim_markup_html_to_xhtml(buf, &xhtml, &jm->body);
|
|
540 g_free(buf);
|
|
541
|
|
542 if(!jbr || jbr->capabilities & JABBER_CAP_XHTML)
|
|
543 jm->xhtml = xhtml;
|
|
544 else
|
|
545 g_free(xhtml);
|
|
546
|
|
547 jabber_message_send(jm);
|
|
548 jabber_message_free(jm);
|
|
549 return 1;
|
|
550 }
|
|
551
|
|
552 int jabber_message_send_chat(GaimConnection *gc, int id, const char *msg, GaimMessageFlags flags)
|
|
553 {
|
|
554 JabberChat *chat;
|
|
555 JabberMessage *jm;
|
|
556 JabberStream *js;
|
|
557 char *buf;
|
|
558
|
|
559 if(!msg || !gc)
|
|
560 return 0;
|
|
561
|
|
562 js = gc->proto_data;
|
|
563 chat = jabber_chat_find_by_id(js, id);
|
|
564
|
|
565 if(!chat)
|
|
566 return 0;
|
|
567
|
|
568 jm = g_new0(JabberMessage, 1);
|
|
569 jm->js = gc->proto_data;
|
|
570 jm->type = JABBER_MESSAGE_GROUPCHAT;
|
|
571 jm->to = g_strdup_printf("%s@%s", chat->room, chat->server);
|
|
572 jm->id = jabber_get_next_id(jm->js);
|
|
573
|
|
574 buf = g_strdup_printf("<html xmlns='http://jabber.org/protocol/xhtml-im'><body xmlns='http://www.w3.org/1999/xhtml'>%s</body></html>", msg);
|
|
575 gaim_markup_html_to_xhtml(buf, &jm->xhtml, &jm->body);
|
|
576 g_free(buf);
|
|
577
|
|
578 if(!chat->xhtml) {
|
|
579 g_free(jm->xhtml);
|
|
580 jm->xhtml = NULL;
|
|
581 }
|
|
582
|
|
583 jabber_message_send(jm);
|
|
584 jabber_message_free(jm);
|
|
585
|
|
586 return 1;
|
|
587 }
|
|
588
|
|
589 unsigned int jabber_send_typing(GaimConnection *gc, const char *who, GaimTypingState state)
|
|
590 {
|
|
591 JabberMessage *jm;
|
|
592 JabberBuddy *jb;
|
|
593 JabberBuddyResource *jbr;
|
|
594 char *resource = jabber_get_resource(who);
|
|
595
|
|
596 jb = jabber_buddy_find(gc->proto_data, who, TRUE);
|
|
597 jbr = jabber_buddy_find_resource(jb, resource);
|
|
598
|
|
599 g_free(resource);
|
|
600
|
|
601 if(!jbr || !((jbr->capabilities & JABBER_CAP_COMPOSING) || (jbr->chat_states != JABBER_CHAT_STATES_UNSUPPORTED)))
|
|
602 return 0;
|
|
603
|
|
604 /* TODO: figure out threading */
|
|
605 jm = g_new0(JabberMessage, 1);
|
|
606 jm->js = gc->proto_data;
|
|
607 jm->type = JABBER_MESSAGE_CHAT;
|
|
608 jm->to = g_strdup(who);
|
|
609 jm->id = jabber_get_next_id(jm->js);
|
|
610
|
|
611 if(GAIM_TYPING == state)
|
|
612 jm->chat_state = JM_STATE_COMPOSING;
|
|
613 else if(GAIM_TYPED == state)
|
|
614 jm->chat_state = JM_STATE_PAUSED;
|
|
615 else
|
|
616 jm->chat_state = JM_STATE_ACTIVE;
|
|
617
|
|
618 if(jbr->chat_states != JABBER_CHAT_STATES_UNSUPPORTED) {
|
|
619 jm->typing_style |= JM_TS_JEP_0085;
|
|
620 /* if(JABBER_CHAT_STATES_UNKNOWN == jbr->chat_states)
|
|
621 jbr->chat_states = JABBER_CHAT_STATES_UNSUPPORTED; */
|
|
622 }
|
|
623
|
|
624 if(jbr->chat_states != JABBER_CHAT_STATES_SUPPORTED)
|
|
625 jm->typing_style |= JM_TS_JEP_0022;
|
|
626
|
|
627 jabber_message_send(jm);
|
|
628 jabber_message_free(jm);
|
|
629
|
|
630 return 0;
|
|
631 }
|
|
632
|