Mercurial > pidgin
annotate src/protocols/jabber/chat.c @ 11454:201617d49573
[gaim-migrate @ 13693]
This commit includes a number of changes:
1. Aliases are now used consistently in chats. If the prpl uses unique screen names for chats (e.g. Jabber), then aliases are not used at all.
2. The chat list is now colorized to match the colors used in the chat itself.
3. Buddies are bolded in the chat user list.
4. Buddies are sorted above non-buddies in the chat user list.
5. The chat user list is ellipsized when possible (i.e. on GTK+ 2.6.0 or above).
6. I've accepted patch #1178248, by Matt Amato to add "buddy-added" and "buddy-removed" signals. These were used in my implementation of #3 and #4, to update the GUI when users are added or removed from the buddy list.
7. I've added a "blist-node-aliased" signal that is emitted when a buddy, contact, or chat is aliased.
8. Since it was hard to separate and I need it at some point, I'm letting it slip in... I've changed GaimConversation.log to be a GList named logs. This way, we can have multiple logs for a single conversation. This will be necessary to implement unnamed chat logging in some reasonable fasion (see my notes in the TODO file).
committer: Tailor Script <tailor@pidgin.im>
author | Richard Laager <rlaager@wiktel.com> |
---|---|
date | Tue, 06 Sep 2005 03:04:07 +0000 |
parents | 1e756e251dc3 |
children | fc464a0abccc |
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 #include "debug.h" | |
9713 | 23 #include "prpl.h" /* for proto_chat_entry */ |
7310 | 24 #include "notify.h" |
8113 | 25 #include "request.h" |
26 #include "roomlist.h" | |
7971 | 27 #include "util.h" |
7014 | 28 |
29 #include "chat.h" | |
7895 | 30 #include "iq.h" |
7014 | 31 #include "message.h" |
7073 | 32 #include "presence.h" |
7923 | 33 #include "xdata.h" |
7014 | 34 |
35 GList *jabber_chat_info(GaimConnection *gc) | |
36 { | |
37 GList *m = NULL; | |
38 struct proto_chat_entry *pce; | |
39 | |
40 pce = g_new0(struct proto_chat_entry, 1); | |
7841 | 41 pce->label = _("_Room:"); |
7014 | 42 pce->identifier = "room"; |
10959 | 43 pce->required = TRUE; |
7014 | 44 m = g_list_append(m, pce); |
45 | |
46 pce = g_new0(struct proto_chat_entry, 1); | |
7841 | 47 pce->label = _("_Server:"); |
7014 | 48 pce->identifier = "server"; |
10959 | 49 pce->required = TRUE; |
7014 | 50 m = g_list_append(m, pce); |
51 | |
52 pce = g_new0(struct proto_chat_entry, 1); | |
7841 | 53 pce->label = _("_Handle:"); |
7014 | 54 pce->identifier = "handle"; |
10959 | 55 pce->required = TRUE; |
7014 | 56 m = g_list_append(m, pce); |
57 | |
58 pce = g_new0(struct proto_chat_entry, 1); | |
7841 | 59 pce->label = _("_Password:"); |
7014 | 60 pce->identifier = "password"; |
61 pce->secret = TRUE; | |
62 m = g_list_append(m, pce); | |
63 | |
64 return m; | |
65 } | |
66 | |
9754 | 67 GHashTable *jabber_chat_info_defaults(GaimConnection *gc, const char *chat_name) |
68 { | |
69 GHashTable *defaults; | |
9770 | 70 JabberStream *js = gc->proto_data; |
9754 | 71 |
72 defaults = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free); | |
73 | |
9770 | 74 g_hash_table_insert(defaults, "handle", g_strdup(js->user->node)); |
75 | |
76 if (js->chat_servers) | |
77 g_hash_table_insert(defaults, "server", g_strdup(js->chat_servers->data)); | |
78 else | |
79 g_hash_table_insert(defaults, "server", g_strdup("conference.jabber.org")); | |
80 | |
9754 | 81 if (chat_name != NULL) { |
9760 | 82 JabberID *jid = jabber_id_new(chat_name); |
83 if(jid) { | |
84 g_hash_table_insert(defaults, "room", g_strdup(jid->node)); | |
85 if(jid->domain) | |
9770 | 86 g_hash_table_replace(defaults, "server", g_strdup(jid->domain)); |
9760 | 87 jabber_id_free(jid); |
88 } | |
9754 | 89 } |
90 | |
91 return defaults; | |
92 } | |
93 | |
7014 | 94 JabberChat *jabber_chat_find(JabberStream *js, const char *room, |
95 const char *server) | |
96 { | |
10607 | 97 JabberChat *chat = NULL; |
7014 | 98 char *room_jid; |
99 | |
10607 | 100 if(NULL != js->chats) |
101 { | |
102 room_jid = g_strdup_printf("%s@%s", room, server); | |
7014 | 103 |
10607 | 104 chat = g_hash_table_lookup(js->chats, jabber_normalize(NULL, room_jid)); |
105 g_free(room_jid); | |
106 } | |
7014 | 107 |
108 return chat; | |
109 } | |
110 | |
111 struct _find_by_id_data { | |
112 int id; | |
113 JabberChat *chat; | |
114 }; | |
115 | |
116 void find_by_id_foreach_cb(gpointer key, gpointer value, gpointer user_data) | |
117 { | |
118 JabberChat *chat = value; | |
119 struct _find_by_id_data *fbid = user_data; | |
120 | |
121 if(chat->id == fbid->id) | |
122 fbid->chat = chat; | |
123 } | |
124 | |
125 JabberChat *jabber_chat_find_by_id(JabberStream *js, int id) | |
126 { | |
127 JabberChat *chat; | |
128 struct _find_by_id_data *fbid = g_new0(struct _find_by_id_data, 1); | |
7073 | 129 fbid->id = id; |
7014 | 130 g_hash_table_foreach(js->chats, find_by_id_foreach_cb, fbid); |
131 chat = fbid->chat; | |
132 g_free(fbid); | |
133 return chat; | |
134 } | |
135 | |
9130 | 136 JabberChat *jabber_chat_find_by_conv(GaimConversation *conv) |
137 { | |
138 GaimAccount *account = gaim_conversation_get_account(conv); | |
139 GaimConnection *gc = gaim_account_get_connection(account); | |
140 JabberStream *js = gc->proto_data; | |
141 int id = gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)); | |
142 | |
143 return jabber_chat_find_by_id(js, id); | |
144 } | |
145 | |
7014 | 146 void jabber_chat_invite(GaimConnection *gc, int id, const char *msg, |
147 const char *name) | |
148 { | |
149 JabberStream *js = gc->proto_data; | |
150 JabberChat *chat; | |
151 xmlnode *message, *body, *x, *invite; | |
152 char *room_jid; | |
153 | |
154 chat = jabber_chat_find_by_id(js, id); | |
155 if(!chat) | |
156 return; | |
157 | |
158 message = xmlnode_new("message"); | |
159 | |
160 room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); | |
161 | |
162 if(chat->muc) { | |
163 xmlnode_set_attrib(message, "to", room_jid); | |
164 x = xmlnode_new_child(message, "x"); | |
165 xmlnode_set_attrib(x, "xmlns", "http://jabber.org/protocol/muc#user"); | |
166 invite = xmlnode_new_child(x, "invite"); | |
167 xmlnode_set_attrib(invite, "to", name); | |
168 body = xmlnode_new_child(invite, "reason"); | |
169 xmlnode_insert_data(body, msg, -1); | |
170 } else { | |
171 xmlnode_set_attrib(message, "to", name); | |
172 body = xmlnode_new_child(message, "body"); | |
173 xmlnode_insert_data(body, msg, -1); | |
174 x = xmlnode_new_child(message, "x"); | |
175 xmlnode_set_attrib(x, "jid", room_jid); | |
176 xmlnode_set_attrib(x, "xmlns", "jabber:x:conference"); | |
177 } | |
178 | |
179 jabber_send(js, message); | |
180 xmlnode_free(message); | |
181 g_free(room_jid); | |
182 } | |
183 | |
9152 | 184 void jabber_chat_member_free(JabberChatMember *jcm); |
185 | |
9917 | 186 char *jabber_get_chat_name(GHashTable *data) { |
187 char *room, *server, *chat_name = NULL; | |
188 | |
189 room = g_hash_table_lookup(data, "room"); | |
190 server = g_hash_table_lookup(data, "server"); | |
191 | |
192 if (room && server) { | |
193 chat_name = g_strdup_printf("%s@%s", room, server); | |
194 } | |
195 return chat_name; | |
196 } | |
197 | |
7014 | 198 void jabber_chat_join(GaimConnection *gc, GHashTable *data) |
199 { | |
200 JabberChat *chat; | |
201 char *room, *server, *handle, *passwd; | |
202 xmlnode *presence, *x; | |
7262 | 203 char *tmp, *room_jid, *full_jid; |
7014 | 204 JabberStream *js = gc->proto_data; |
9954 | 205 GaimPresence *gpresence; |
206 GaimStatus *status; | |
207 JabberBuddyState state; | |
208 const char *msg; | |
209 int priority; | |
7014 | 210 |
211 room = g_hash_table_lookup(data, "room"); | |
212 server = g_hash_table_lookup(data, "server"); | |
213 handle = g_hash_table_lookup(data, "handle"); | |
214 passwd = g_hash_table_lookup(data, "password"); | |
215 | |
8113 | 216 if(!room || !server) |
7014 | 217 return; |
218 | |
8113 | 219 if(!handle) |
220 handle = js->user->node; | |
221 | |
7310 | 222 if(!jabber_nodeprep_validate(room)) { |
223 char *buf = g_strdup_printf(_("%s is not a valid room name"), room); | |
224 gaim_notify_error(gc, _("Invalid Room Name"), _("Invalid Room Name"), | |
225 buf); | |
226 g_free(buf); | |
227 return; | |
228 } else if(!jabber_nameprep_validate(server)) { | |
229 char *buf = g_strdup_printf(_("%s is not a valid server name"), server); | |
230 gaim_notify_error(gc, _("Invalid Server Name"), | |
231 _("Invalid Server Name"), buf); | |
232 g_free(buf); | |
233 return; | |
234 } else if(!jabber_resourceprep_validate(handle)) { | |
235 char *buf = g_strdup_printf(_("%s is not a valid room handle"), handle); | |
236 gaim_notify_error(gc, _("Invalid Room Handle"), | |
237 _("Invalid Room Handle"), buf); | |
238 } | |
239 | |
7014 | 240 if(jabber_chat_find(js, room, server)) |
241 return; | |
242 | |
7262 | 243 tmp = g_strdup_printf("%s@%s", room, server); |
7322 | 244 room_jid = g_strdup(jabber_normalize(NULL, tmp)); |
7262 | 245 g_free(tmp); |
7014 | 246 |
247 chat = g_new0(JabberChat, 1); | |
248 chat->js = gc->proto_data; | |
249 | |
250 chat->room = g_strdup(room); | |
251 chat->server = g_strdup(server); | |
8400 | 252 chat->handle = g_strdup(handle); |
7014 | 253 |
9152 | 254 chat->members = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, |
255 (GDestroyNotify)jabber_chat_member_free); | |
256 | |
7014 | 257 g_hash_table_insert(js->chats, room_jid, chat); |
258 | |
9954 | 259 gpresence = gaim_account_get_presence(gc->account); |
260 status = gaim_presence_get_active_status(gpresence); | |
261 | |
262 gaim_status_to_jabber(status, &state, &msg, &priority); | |
263 | |
264 presence = jabber_presence_create(state, msg, priority); | |
7014 | 265 full_jid = g_strdup_printf("%s/%s", room_jid, handle); |
266 xmlnode_set_attrib(presence, "to", full_jid); | |
267 g_free(full_jid); | |
268 | |
269 x = xmlnode_new_child(presence, "x"); | |
270 xmlnode_set_attrib(x, "xmlns", "http://jabber.org/protocol/muc"); | |
271 | |
272 if(passwd && *passwd) { | |
273 xmlnode *password = xmlnode_new_child(x, "password"); | |
274 xmlnode_insert_data(password, passwd, -1); | |
275 } | |
276 | |
277 jabber_send(js, presence); | |
278 xmlnode_free(presence); | |
279 } | |
280 | |
281 void jabber_chat_leave(GaimConnection *gc, int id) | |
282 { | |
283 JabberStream *js = gc->proto_data; | |
284 JabberChat *chat = jabber_chat_find_by_id(js, id); | |
7974 | 285 |
7014 | 286 |
287 if(!chat) | |
288 return; | |
289 | |
7974 | 290 jabber_chat_part(chat, NULL); |
9152 | 291 |
292 chat->conv = NULL; | |
7014 | 293 } |
294 | |
295 void jabber_chat_destroy(JabberChat *chat) | |
296 { | |
297 JabberStream *js = chat->js; | |
298 char *room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); | |
299 | |
7322 | 300 g_hash_table_remove(js->chats, jabber_normalize(NULL, room_jid)); |
7014 | 301 g_free(room_jid); |
8396 | 302 } |
303 | |
304 void jabber_chat_free(JabberChat *chat) | |
305 { | |
306 if(chat->config_dialog_handle) | |
307 gaim_request_close(chat->config_dialog_type, chat->config_dialog_handle); | |
7014 | 308 |
309 g_free(chat->room); | |
310 g_free(chat->server); | |
10504 | 311 g_free(chat->handle); |
312 g_hash_table_destroy(chat->members); | |
7014 | 313 g_free(chat); |
314 } | |
315 | |
316 gboolean jabber_chat_find_buddy(GaimConversation *conv, const char *name) | |
317 { | |
9554 | 318 return gaim_conv_chat_find_user(GAIM_CONV_CHAT(conv), name); |
7014 | 319 } |
320 | |
7398 | 321 char *jabber_chat_buddy_real_name(GaimConnection *gc, int id, const char *who) |
322 { | |
323 JabberStream *js = gc->proto_data; | |
324 JabberChat *chat; | |
325 | |
326 chat = jabber_chat_find_by_id(js, id); | |
327 | |
328 if(!chat) | |
329 return NULL; | |
330 | |
331 return g_strdup_printf("%s@%s/%s", chat->room, chat->server, who); | |
332 } | |
7895 | 333 |
7923 | 334 static void jabber_chat_room_configure_x_data_cb(JabberStream *js, xmlnode *result, gpointer data) |
335 { | |
336 JabberChat *chat = data; | |
337 xmlnode *query; | |
338 JabberIq *iq; | |
339 char *to = g_strdup_printf("%s@%s", chat->room, chat->server); | |
340 | |
341 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "http://jabber.org/protocol/muc#owner"); | |
342 xmlnode_set_attrib(iq->node, "to", to); | |
343 g_free(to); | |
344 | |
345 query = xmlnode_get_child(iq->node, "query"); | |
346 | |
347 xmlnode_insert_child(query, result); | |
348 | |
349 jabber_iq_send(iq); | |
350 } | |
351 | |
352 static void jabber_chat_room_configure_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
353 { | |
354 xmlnode *query, *x; | |
355 const char *type = xmlnode_get_attrib(packet, "type"); | |
356 const char *from = xmlnode_get_attrib(packet, "from"); | |
7926 | 357 char *msg; |
7923 | 358 JabberChat *chat; |
359 JabberID *jid; | |
360 | |
361 if(!type || !from) | |
362 return; | |
363 | |
364 | |
7926 | 365 |
7923 | 366 if(!strcmp(type, "result")) { |
367 jid = jabber_id_new(from); | |
368 | |
369 if(!jid) | |
370 return; | |
371 | |
372 chat = jabber_chat_find(js, jid->node, jid->domain); | |
373 jabber_id_free(jid); | |
374 | |
375 if(!chat) | |
376 return; | |
377 | |
378 if(!(query = xmlnode_get_child(packet, "query"))) | |
379 return; | |
380 | |
8135 | 381 for(x = xmlnode_get_child(query, "x"); x; x = xmlnode_get_next_twin(x)) { |
7923 | 382 const char *xmlns; |
383 if(!(xmlns = xmlnode_get_attrib(x, "xmlns"))) | |
384 continue; | |
385 | |
386 if(!strcmp(xmlns, "jabber:x:data")) { | |
8396 | 387 chat->config_dialog_type = GAIM_REQUEST_FIELDS; |
388 chat->config_dialog_handle = jabber_x_data_request(js, x, jabber_chat_room_configure_x_data_cb, chat); | |
7923 | 389 return; |
390 } | |
391 } | |
7926 | 392 } else if(!strcmp(type, "error")) { |
8401 | 393 char *msg = jabber_parse_error(js, packet); |
7926 | 394 |
395 gaim_notify_error(js->gc, _("Configuration error"), _("Configuration error"), msg); | |
396 | |
8401 | 397 if(msg) |
398 g_free(msg); | |
7926 | 399 return; |
7923 | 400 } |
401 | |
7926 | 402 msg = g_strdup_printf("Unable to configure room %s", from); |
403 | |
404 gaim_notify_info(js->gc, _("Unable to configure"), _("Unable to configure"), msg); | |
405 g_free(msg); | |
7923 | 406 |
407 } | |
408 | |
409 void jabber_chat_request_room_configure(JabberChat *chat) { | |
410 JabberIq *iq; | |
411 xmlnode *query; | |
412 char *room_jid; | |
413 | |
7895 | 414 if(!chat) |
415 return; | |
416 | |
8396 | 417 chat->config_dialog_handle = NULL; |
418 | |
7955 | 419 if(!chat->muc) { |
420 gaim_notify_error(chat->js->gc, _("Room Configuration Error"), _("Room Configuration Error"), | |
421 _("This room is not capable of being configured")); | |
422 return; | |
423 } | |
424 | |
10474 | 425 iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET, |
7923 | 426 "http://jabber.org/protocol/muc#owner"); |
427 query = xmlnode_get_child(iq->node, "query"); | |
428 room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); | |
7895 | 429 |
7923 | 430 xmlnode_set_attrib(iq->node, "to", room_jid); |
431 | |
432 jabber_iq_set_callback(iq, jabber_chat_room_configure_cb, NULL); | |
433 | |
434 jabber_iq_send(iq); | |
435 | |
436 g_free(room_jid); | |
7895 | 437 } |
438 | |
439 void jabber_chat_create_instant_room(JabberChat *chat) { | |
440 JabberIq *iq; | |
441 xmlnode *query, *x; | |
442 char *room_jid; | |
443 | |
444 if(!chat) | |
445 return; | |
446 | |
8396 | 447 chat->config_dialog_handle = NULL; |
448 | |
7895 | 449 iq = jabber_iq_new_query(chat->js, JABBER_IQ_SET, |
450 "http://jabber.org/protocol/muc#owner"); | |
451 query = xmlnode_get_child(iq->node, "query"); | |
452 x = xmlnode_new_child(query, "x"); | |
453 room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); | |
454 | |
455 xmlnode_set_attrib(iq->node, "to", room_jid); | |
456 xmlnode_set_attrib(x, "xmlns", "jabber:x:data"); | |
457 xmlnode_set_attrib(x, "type", "submit"); | |
458 | |
459 jabber_iq_send(iq); | |
460 | |
461 g_free(room_jid); | |
462 } | |
7955 | 463 |
464 static void jabber_chat_register_x_data_result_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
465 { | |
466 const char *type = xmlnode_get_attrib(packet, "type"); | |
467 | |
468 if(type && !strcmp(type, "error")) { | |
8401 | 469 char *msg = jabber_parse_error(js, packet); |
470 | |
471 gaim_notify_error(js->gc, _("Registration error"), _("Registration error"), msg); | |
472 | |
473 if(msg) | |
474 g_free(msg); | |
475 return; | |
7955 | 476 } |
477 } | |
478 | |
479 static void jabber_chat_register_x_data_cb(JabberStream *js, xmlnode *result, gpointer data) | |
480 { | |
481 JabberChat *chat = data; | |
482 xmlnode *query; | |
483 JabberIq *iq; | |
484 char *to = g_strdup_printf("%s@%s", chat->room, chat->server); | |
485 | |
486 iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:register"); | |
487 xmlnode_set_attrib(iq->node, "to", to); | |
488 g_free(to); | |
489 | |
490 query = xmlnode_get_child(iq->node, "query"); | |
491 | |
492 xmlnode_insert_child(query, result); | |
493 | |
494 jabber_iq_set_callback(iq, jabber_chat_register_x_data_result_cb, NULL); | |
495 | |
496 jabber_iq_send(iq); | |
497 } | |
498 | |
499 static void jabber_chat_register_cb(JabberStream *js, xmlnode *packet, gpointer data) | |
500 { | |
501 xmlnode *query, *x; | |
502 const char *type = xmlnode_get_attrib(packet, "type"); | |
503 const char *from = xmlnode_get_attrib(packet, "from"); | |
504 char *msg; | |
505 JabberChat *chat; | |
506 JabberID *jid; | |
507 | |
508 if(!type || !from) | |
509 return; | |
510 | |
511 if(!strcmp(type, "result")) { | |
512 jid = jabber_id_new(from); | |
513 | |
514 if(!jid) | |
515 return; | |
516 | |
517 chat = jabber_chat_find(js, jid->node, jid->domain); | |
518 jabber_id_free(jid); | |
519 | |
520 if(!chat) | |
521 return; | |
522 | |
523 if(!(query = xmlnode_get_child(packet, "query"))) | |
524 return; | |
525 | |
8135 | 526 for(x = xmlnode_get_child(query, "x"); x; x = xmlnode_get_next_twin(x)) { |
7955 | 527 const char *xmlns; |
528 | |
529 if(!(xmlns = xmlnode_get_attrib(x, "xmlns"))) | |
530 continue; | |
531 | |
532 if(!strcmp(xmlns, "jabber:x:data")) { | |
533 jabber_x_data_request(js, x, jabber_chat_register_x_data_cb, chat); | |
534 return; | |
535 } | |
536 } | |
537 } else if(!strcmp(type, "error")) { | |
8401 | 538 char *msg = jabber_parse_error(js, packet); |
7955 | 539 |
540 gaim_notify_error(js->gc, _("Registration error"), _("Registration error"), msg); | |
541 | |
8401 | 542 if(msg) |
543 g_free(msg); | |
7955 | 544 return; |
545 } | |
546 | |
547 msg = g_strdup_printf("Unable to configure room %s", from); | |
548 | |
549 gaim_notify_info(js->gc, _("Unable to configure"), _("Unable to configure"), msg); | |
550 g_free(msg); | |
551 | |
552 } | |
553 | |
554 void jabber_chat_register(JabberChat *chat) | |
555 { | |
556 JabberIq *iq; | |
557 char *room_jid; | |
558 | |
559 if(!chat) | |
560 return; | |
561 | |
562 room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); | |
563 | |
564 iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET, "jabber:iq:register"); | |
565 xmlnode_set_attrib(iq->node, "to", room_jid); | |
566 g_free(room_jid); | |
567 | |
568 jabber_iq_set_callback(iq, jabber_chat_register_cb, NULL); | |
569 | |
570 jabber_iq_send(iq); | |
571 } | |
572 | |
7971 | 573 /* merge this with the function below when we get everyone on the same page wrt /commands */ |
574 void jabber_chat_change_topic(JabberChat *chat, const char *topic) | |
575 { | |
576 if(topic && *topic) { | |
577 JabberMessage *jm; | |
578 jm = g_new0(JabberMessage, 1); | |
579 jm->js = chat->js; | |
580 jm->type = JABBER_MESSAGE_GROUPCHAT; | |
581 jm->subject = gaim_markup_strip_html(topic); | |
582 jm->to = g_strdup_printf("%s@%s", chat->room, chat->server); | |
583 jabber_message_send(jm); | |
584 jabber_message_free(jm); | |
585 } else { | |
586 const char *cur = gaim_conv_chat_get_topic(GAIM_CONV_CHAT(chat->conv)); | |
9762 | 587 char *buf, *tmp, *tmp2; |
7955 | 588 |
9762 | 589 if(cur) { |
10732
c4cb90065e1d
[gaim-migrate @ 12334]
Luke Schierer <lschiere@pidgin.im>
parents:
10607
diff
changeset
|
590 tmp = g_markup_escape_text(cur, -1); |
9762 | 591 tmp2 = gaim_markup_linkify(tmp); |
592 buf = g_strdup_printf(_("current topic is: %s"), tmp2); | |
593 g_free(tmp); | |
594 g_free(tmp2); | |
595 } else | |
7971 | 596 buf = g_strdup(_("No topic is set")); |
597 gaim_conv_chat_write(GAIM_CONV_CHAT(chat->conv), "", buf, | |
598 GAIM_MESSAGE_SYSTEM | GAIM_MESSAGE_NO_LOG, time(NULL)); | |
599 g_free(buf); | |
600 } | |
601 | |
602 } | |
603 | |
604 void jabber_chat_set_topic(GaimConnection *gc, int id, const char *topic) | |
605 { | |
606 JabberStream *js = gc->proto_data; | |
607 JabberChat *chat = jabber_chat_find_by_id(js, id); | |
608 | |
609 if(!chat) | |
610 return; | |
611 | |
612 jabber_chat_change_topic(chat, topic); | |
613 } | |
614 | |
615 | |
7972 | 616 void jabber_chat_change_nick(JabberChat *chat, const char *nick) |
617 { | |
618 xmlnode *presence; | |
619 char *full_jid; | |
9954 | 620 GaimPresence *gpresence; |
621 GaimStatus *status; | |
622 JabberBuddyState state; | |
623 const char *msg; | |
624 int priority; | |
7972 | 625 |
626 if(!chat->muc) { | |
627 gaim_conv_chat_write(GAIM_CONV_CHAT(chat->conv), "", | |
628 _("Nick changing not supported in non-MUC chatrooms"), | |
629 GAIM_MESSAGE_SYSTEM, time(NULL)); | |
630 return; | |
631 } | |
632 | |
9954 | 633 gpresence = gaim_account_get_presence(chat->js->gc->account); |
634 status = gaim_presence_get_active_status(gpresence); | |
635 | |
636 gaim_status_to_jabber(status, &state, &msg, &priority); | |
637 | |
638 presence = jabber_presence_create(state, msg, priority); | |
7972 | 639 full_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, nick); |
640 xmlnode_set_attrib(presence, "to", full_jid); | |
641 g_free(full_jid); | |
642 | |
643 jabber_send(chat->js, presence); | |
644 xmlnode_free(presence); | |
645 } | |
646 | |
7974 | 647 void jabber_chat_part(JabberChat *chat, const char *msg) |
648 { | |
649 char *room_jid; | |
650 xmlnode *presence; | |
7972 | 651 |
8537 | 652 room_jid = g_strdup_printf("%s@%s/%s", chat->room, chat->server, |
653 chat->handle); | |
7974 | 654 presence = xmlnode_new("presence"); |
655 xmlnode_set_attrib(presence, "to", room_jid); | |
656 xmlnode_set_attrib(presence, "type", "unavailable"); | |
657 if(msg) { | |
658 xmlnode *status = xmlnode_new_child(presence, "status"); | |
659 xmlnode_insert_data(status, msg, -1); | |
660 } | |
661 jabber_send(chat->js, presence); | |
662 xmlnode_free(presence); | |
663 g_free(room_jid); | |
664 } | |
665 | |
8113 | 666 static void roomlist_disco_result_cb(JabberStream *js, xmlnode *packet, gpointer data) |
667 { | |
668 xmlnode *query; | |
669 xmlnode *item; | |
670 const char *type; | |
7974 | 671 |
8113 | 672 if(!js->roomlist) |
673 return; | |
674 | |
675 if(!(type = xmlnode_get_attrib(packet, "type")) || strcmp(type, "result")) { | |
8401 | 676 char *err = jabber_parse_error(js,packet); |
10091 | 677 gaim_notify_error(js->gc, _("Error"), |
10094 | 678 _("Error retrieving room list"), err); |
8113 | 679 gaim_roomlist_set_in_progress(js->roomlist, FALSE); |
8120 | 680 gaim_roomlist_unref(js->roomlist); |
681 js->roomlist = NULL; | |
8401 | 682 g_free(err); |
8113 | 683 return; |
684 } | |
685 | |
686 if(!(query = xmlnode_get_child(packet, "query"))) { | |
8401 | 687 char *err = jabber_parse_error(js, packet); |
10091 | 688 gaim_notify_error(js->gc, _("Error"), |
10094 | 689 _("Error retrieving room list"), err); |
8113 | 690 gaim_roomlist_set_in_progress(js->roomlist, FALSE); |
8120 | 691 gaim_roomlist_unref(js->roomlist); |
692 js->roomlist = NULL; | |
8401 | 693 g_free(err); |
8113 | 694 return; |
695 } | |
696 | |
8135 | 697 for(item = xmlnode_get_child(query, "item"); item; |
698 item = xmlnode_get_next_twin(item)) { | |
8113 | 699 const char *name; |
700 GaimRoomlistRoom *room; | |
701 JabberID *jid; | |
702 | |
703 if(!(jid = jabber_id_new(xmlnode_get_attrib(item, "jid")))) | |
704 continue; | |
705 name = xmlnode_get_attrib(item, "name"); | |
706 | |
707 | |
708 room = gaim_roomlist_room_new(GAIM_ROOMLIST_ROOMTYPE_ROOM, jid->node, NULL); | |
709 gaim_roomlist_room_add_field(js->roomlist, room, jid->node); | |
710 gaim_roomlist_room_add_field(js->roomlist, room, jid->domain); | |
711 gaim_roomlist_room_add_field(js->roomlist, room, name ? name : ""); | |
712 gaim_roomlist_room_add(js->roomlist, room); | |
713 | |
714 jabber_id_free(jid); | |
715 } | |
716 gaim_roomlist_set_in_progress(js->roomlist, FALSE); | |
717 gaim_roomlist_unref(js->roomlist); | |
718 js->roomlist = NULL; | |
719 } | |
720 | |
10045 | 721 static void roomlist_cancel_cb(JabberStream *js, const char *server) { |
722 if(js->roomlist) { | |
723 gaim_roomlist_set_in_progress(js->roomlist, FALSE); | |
724 gaim_roomlist_unref(js->roomlist); | |
725 js->roomlist = NULL; | |
726 } | |
727 } | |
728 | |
8113 | 729 static void roomlist_ok_cb(JabberStream *js, const char *server) |
730 { | |
731 JabberIq *iq; | |
10045 | 732 |
733 if(!js->roomlist) | |
734 return; | |
8113 | 735 |
736 if(!server || !*server) { | |
737 gaim_notify_error(js->gc, _("Invalid Server"), _("Invalid Server"), NULL); | |
738 return; | |
739 } | |
740 | |
10045 | 741 gaim_roomlist_set_in_progress(js->roomlist, TRUE); |
742 | |
743 iq = jabber_iq_new_query(js, JABBER_IQ_GET, "http://jabber.org/protocol/disco#items"); | |
744 | |
745 xmlnode_set_attrib(iq->node, "to", server); | |
746 | |
747 jabber_iq_set_callback(iq, roomlist_disco_result_cb, NULL); | |
748 | |
749 jabber_iq_send(iq); | |
750 } | |
751 | |
752 GaimRoomlist *jabber_roomlist_get_list(GaimConnection *gc) | |
753 { | |
754 JabberStream *js = gc->proto_data; | |
755 GList *fields = NULL; | |
756 GaimRoomlistField *f; | |
757 | |
9913 | 758 if(js->roomlist) |
759 gaim_roomlist_unref(js->roomlist); | |
760 | |
761 js->roomlist = gaim_roomlist_new(gaim_connection_get_account(js->gc)); | |
762 | |
763 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "room", TRUE); | |
764 fields = g_list_append(fields, f); | |
765 | |
766 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, "", "server", TRUE); | |
767 fields = g_list_append(fields, f); | |
768 | |
769 f = gaim_roomlist_field_new(GAIM_ROOMLIST_FIELD_STRING, _("Description"), "description", FALSE); | |
770 fields = g_list_append(fields, f); | |
771 | |
772 gaim_roomlist_set_fields(js->roomlist, fields); | |
773 | |
8113 | 774 |
775 gaim_request_input(gc, _("Enter a Conference Server"), _("Enter a Conference Server"), | |
776 _("Select a conference server to query"), | |
777 js->chat_servers ? js->chat_servers->data : "conference.jabber.org", | |
8697 | 778 FALSE, FALSE, NULL, |
10045 | 779 _("Find Rooms"), GAIM_CALLBACK(roomlist_ok_cb), |
780 _("Cancel"), GAIM_CALLBACK(roomlist_cancel_cb), js); | |
8113 | 781 |
782 return js->roomlist; | |
783 } | |
784 | |
785 void jabber_roomlist_cancel(GaimRoomlist *list) | |
786 { | |
787 GaimConnection *gc; | |
788 JabberStream *js; | |
789 | |
790 gc = gaim_account_get_connection(list->account); | |
791 js = gc->proto_data; | |
792 | |
793 gaim_roomlist_set_in_progress(list, FALSE); | |
794 | |
795 if (js->roomlist == list) { | |
796 js->roomlist = NULL; | |
797 gaim_roomlist_unref(list); | |
798 } | |
799 } | |
800 | |
9152 | 801 void jabber_chat_member_free(JabberChatMember *jcm) |
802 { | |
803 g_free(jcm->handle); | |
804 g_free(jcm->jid); | |
805 g_free(jcm); | |
806 } | |
807 | |
808 void jabber_chat_track_handle(JabberChat *chat, const char *handle, | |
809 const char *jid, const char *affiliation, const char *role) | |
810 { | |
811 JabberChatMember *jcm = g_new0(JabberChatMember, 1); | |
812 | |
813 jcm->handle = g_strdup(handle); | |
814 jcm->jid = g_strdup(jid); | |
815 | |
816 g_hash_table_replace(chat->members, jcm->handle, jcm); | |
817 | |
818 /* XXX: keep track of role and affiliation */ | |
819 } | |
820 | |
821 void jabber_chat_remove_handle(JabberChat *chat, const char *handle) | |
822 { | |
823 g_hash_table_remove(chat->members, handle); | |
824 } | |
825 | |
826 gboolean jabber_chat_ban_user(JabberChat *chat, const char *who, const char *why) | |
827 { | |
828 JabberIq *iq; | |
829 JabberChatMember *jcm = g_hash_table_lookup(chat->members, who); | |
830 char *to; | |
831 xmlnode *query, *item, *reason; | |
832 | |
833 if(!jcm || !jcm->jid) | |
834 return FALSE; | |
835 | |
836 iq = jabber_iq_new_query(chat->js, JABBER_IQ_SET, | |
837 "http://jabber.org/protocol/muc#admin"); | |
838 | |
839 to = g_strdup_printf("%s@%s", chat->room, chat->server); | |
840 xmlnode_set_attrib(iq->node, "to", to); | |
841 g_free(to); | |
842 | |
843 query = xmlnode_get_child(iq->node, "query"); | |
844 item = xmlnode_new_child(query, "item"); | |
845 xmlnode_set_attrib(item, "jid", jcm->jid); | |
846 xmlnode_set_attrib(item, "affiliation", "outcast"); | |
847 if(why) { | |
848 reason = xmlnode_new_child(item, "reason"); | |
849 xmlnode_insert_data(reason, why, -1); | |
850 } | |
851 | |
852 jabber_iq_send(iq); | |
853 | |
854 return TRUE; | |
855 } | |
8113 | 856 |
11393 | 857 gboolean jabber_chat_affiliate_user(JabberChat *chat, const char *who, const char *affiliation) |
858 { | |
859 JabberIq *iq; | |
860 JabberChatMember *jcm = g_hash_table_lookup(chat->members, who); | |
861 char *to; | |
862 xmlnode *query, *item; | |
863 | |
864 if (!jcm || !jcm->jid) | |
865 return FALSE; | |
866 | |
867 iq = jabber_iq_new_query(chat->js, JABBER_IQ_SET, | |
868 "http://jabber.org/protocol/muc#admin"); | |
869 | |
870 to = g_strdup_printf("%s@%s", chat->room, chat->server); | |
871 xmlnode_set_attrib(iq->node, "to", to); | |
872 g_free(to); | |
873 | |
874 query = xmlnode_get_child(iq->node, "query"); | |
875 item = xmlnode_new_child(query, "item"); | |
876 xmlnode_set_attrib(item, "jid", jcm->jid); | |
877 xmlnode_set_attrib(item, "affiliation", affiliation); | |
878 | |
879 jabber_iq_send(iq); | |
880 | |
881 return TRUE; | |
882 } | |
8113 | 883 |
9152 | 884 gboolean jabber_chat_kick_user(JabberChat *chat, const char *who, const char *why) |
885 { | |
886 JabberIq *iq; | |
887 JabberChatMember *jcm = g_hash_table_lookup(chat->members, who); | |
888 char *to; | |
889 xmlnode *query, *item, *reason; | |
890 | |
891 if(!jcm || !jcm->jid) | |
892 return FALSE; | |
893 | |
894 iq = jabber_iq_new_query(chat->js, JABBER_IQ_SET, | |
895 "http://jabber.org/protocol/muc#admin"); | |
896 | |
897 to = g_strdup_printf("%s@%s", chat->room, chat->server); | |
898 xmlnode_set_attrib(iq->node, "to", to); | |
899 g_free(to); | |
900 | |
901 query = xmlnode_get_child(iq->node, "query"); | |
902 item = xmlnode_new_child(query, "item"); | |
903 xmlnode_set_attrib(item, "jid", jcm->jid); | |
904 xmlnode_set_attrib(item, "role", "none"); | |
905 if(why) { | |
906 reason = xmlnode_new_child(item, "reason"); | |
907 xmlnode_insert_data(reason, why, -1); | |
908 } | |
909 | |
910 jabber_iq_send(iq); | |
911 | |
912 return TRUE; | |
913 } | |
914 | |
10941 | 915 static void jabber_chat_disco_traffic_cb(JabberStream *js, xmlnode *packet, gpointer data) |
916 { | |
917 JabberChat *chat; | |
918 xmlnode *query, *x, *error; | |
919 int id = GPOINTER_TO_INT(data); | |
920 | |
921 if(!(chat = jabber_chat_find_by_id(js, id))) | |
922 return; | |
923 | |
11392 | 924 /* defaults, in case the conference server doesn't |
925 * support this request */ | |
926 chat->xhtml = TRUE; | |
927 | |
10941 | 928 if((error = xmlnode_get_child(packet, "error"))) { |
929 return; | |
930 } | |
931 | |
932 if(!(query = xmlnode_get_child(packet, "query"))) | |
933 return; | |
934 | |
11392 | 935 chat->xhtml = FALSE; |
936 | |
10941 | 937 for(x = xmlnode_get_child(query, "feature"); x; x = xmlnode_get_next_twin(x)) { |
938 const char *var = xmlnode_get_attrib(x, "var"); | |
939 | |
940 if(var && !strcmp(var, "http://jabber.org/protocol/xhtml-im")) { | |
941 chat->xhtml = TRUE; | |
942 } | |
943 } | |
944 } | |
945 | |
946 void jabber_chat_disco_traffic(JabberChat *chat) | |
947 { | |
948 JabberIq *iq; | |
949 xmlnode *query; | |
11392 | 950 char *room_jid; |
951 | |
952 room_jid = g_strdup_printf("%s@%s", chat->room, chat->server); | |
10941 | 953 |
954 iq = jabber_iq_new_query(chat->js, JABBER_IQ_GET, | |
955 "http://jabber.org/protocol/disco#info"); | |
956 | |
11392 | 957 xmlnode_set_attrib(iq->node, "to", room_jid); |
958 | |
10941 | 959 query = xmlnode_get_child(iq->node, "query"); |
960 | |
961 xmlnode_set_attrib(query, "node", "http://jabber.org/protocol/muc#traffic"); | |
962 | |
963 jabber_iq_set_callback(iq, jabber_chat_disco_traffic_cb, GINT_TO_POINTER(chat->id)); | |
964 | |
965 jabber_iq_send(iq); | |
11392 | 966 |
967 g_free(room_jid); | |
10941 | 968 } |
9152 | 969 |
970 | |
10941 | 971 |