comparison libpurple/conversation.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 32c366eeeb99
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
1 /*
2 * gaim
3 *
4 * Gaim is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
6 * source distribution.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22 #include "internal.h"
23 #include "blist.h"
24 #include "conversation.h"
25 #include "dbus-maybe.h"
26 #include "debug.h"
27 #include "imgstore.h"
28 #include "notify.h"
29 #include "prefs.h"
30 #include "prpl.h"
31 #include "request.h"
32 #include "signals.h"
33 #include "util.h"
34
35 #define SEND_TYPED_TIMEOUT 5000
36
37 static GList *conversations = NULL;
38 static GList *ims = NULL;
39 static GList *chats = NULL;
40 static GaimConversationUiOps *default_ops = NULL;
41
42 void
43 gaim_conversations_set_ui_ops(GaimConversationUiOps *ops)
44 {
45 default_ops = ops;
46 }
47
48 static gboolean
49 reset_typing_cb(gpointer data)
50 {
51 GaimConversation *c = (GaimConversation *)data;
52 GaimConvIm *im;
53
54 im = GAIM_CONV_IM(c);
55
56 gaim_conv_im_set_typing_state(im, GAIM_NOT_TYPING);
57 gaim_conv_im_update_typing(im);
58 gaim_conv_im_stop_typing_timeout(im);
59
60 return FALSE;
61 }
62
63 static gboolean
64 send_typed_cb(gpointer data)
65 {
66 GaimConversation *conv = (GaimConversation *)data;
67 GaimConnection *gc;
68 const char *name;
69
70 g_return_val_if_fail(conv != NULL, FALSE);
71
72 gc = gaim_conversation_get_gc(conv);
73 name = gaim_conversation_get_name(conv);
74
75 if (gc != NULL && name != NULL) {
76 /* We set this to 1 so that GAIM_TYPING will be sent
77 * if the Gaim user types anything else.
78 */
79 gaim_conv_im_set_type_again(GAIM_CONV_IM(conv), 1);
80
81 serv_send_typing(gc, name, GAIM_TYPED);
82 gaim_signal_emit(gaim_conversations_get_handle(),
83 "buddy-typed", conv->account, conv->name);
84
85 gaim_debug(GAIM_DEBUG_MISC, "conversation", "typed...\n");
86 }
87
88 return FALSE;
89 }
90
91 static void
92 common_send(GaimConversation *conv, const char *message, GaimMessageFlags msgflags)
93 {
94 GaimConversationType type;
95 GaimAccount *account;
96 GaimConnection *gc;
97 char *displayed = NULL, *sent = NULL;
98 int err = 0;
99
100 if (strlen(message) == 0)
101 return;
102
103 account = gaim_conversation_get_account(conv);
104 gc = gaim_conversation_get_gc(conv);
105
106 g_return_if_fail(account != NULL);
107 g_return_if_fail(gc != NULL);
108
109 type = gaim_conversation_get_type(conv);
110
111 /* Always linkfy the text for display */
112 displayed = gaim_markup_linkify(message);
113
114 if ((conv->features & GAIM_CONNECTION_HTML) &&
115 !(msgflags & GAIM_MESSAGE_RAW))
116 {
117 sent = g_strdup(displayed);
118 }
119 else
120 sent = g_strdup(message);
121
122 msgflags |= GAIM_MESSAGE_SEND;
123
124 if (type == GAIM_CONV_TYPE_IM) {
125 GaimConvIm *im = GAIM_CONV_IM(conv);
126
127 gaim_signal_emit(gaim_conversations_get_handle(), "sending-im-msg",
128 account,
129 gaim_conversation_get_name(conv), &sent);
130
131 if (sent != NULL && sent[0] != '\0') {
132
133 err = serv_send_im(gc, gaim_conversation_get_name(conv),
134 sent, msgflags);
135
136 if ((err > 0) && (displayed != NULL))
137 gaim_conv_im_write(im, NULL, displayed, msgflags, time(NULL));
138
139 gaim_signal_emit(gaim_conversations_get_handle(), "sent-im-msg",
140 account,
141 gaim_conversation_get_name(conv), sent);
142 }
143 }
144 else {
145 gaim_signal_emit(gaim_conversations_get_handle(), "sending-chat-msg",
146 account, &sent,
147 gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)));
148
149 if (sent != NULL && sent[0] != '\0') {
150 err = serv_chat_send(gc, gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)), sent, msgflags);
151
152 gaim_signal_emit(gaim_conversations_get_handle(), "sent-chat-msg",
153 account, sent,
154 gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)));
155 }
156 }
157
158 if (err < 0) {
159 const char *who;
160 const char *msg;
161
162 who = gaim_conversation_get_name(conv);
163
164 if (err == -E2BIG) {
165 msg = _("Unable to send message: The message is too large.");
166
167 if (!gaim_conv_present_error(who, account, msg)) {
168 char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
169 gaim_notify_error(gc, NULL, msg2, _("The message is too large."));
170 g_free(msg2);
171 }
172 }
173 else if (err == -ENOTCONN) {
174 gaim_debug(GAIM_DEBUG_ERROR, "conversation",
175 "Not yet connected.\n");
176 }
177 else {
178 msg = _("Unable to send message.");
179
180 if (!gaim_conv_present_error(who, account, msg)) {
181 char *msg2 = g_strdup_printf(_("Unable to send message to %s."), who);
182 gaim_notify_error(gc, NULL, msg2, NULL);
183 g_free(msg2);
184 }
185 }
186 }
187
188 g_free(displayed);
189 g_free(sent);
190 }
191
192 static void
193 open_log(GaimConversation *conv)
194 {
195 conv->logs = g_list_append(NULL, gaim_log_new(conv->type == GAIM_CONV_TYPE_CHAT ? GAIM_LOG_CHAT :
196 GAIM_LOG_IM, conv->name, conv->account,
197 conv, time(NULL), NULL));
198 }
199
200
201 /**************************************************************************
202 * Conversation API
203 **************************************************************************/
204 static void
205 gaim_conversation_chat_cleanup_for_rejoin(GaimConversation *conv)
206 {
207 const char *disp;
208 GaimAccount *account;
209 GaimConnection *gc;
210
211 account = gaim_conversation_get_account(conv);
212
213 gaim_conversation_close_logs(conv);
214 open_log(conv);
215
216 gc = gaim_account_get_connection(account);
217
218 if ((disp = gaim_connection_get_display_name(gc)) != NULL)
219 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(conv), disp);
220 else
221 {
222 gaim_conv_chat_set_nick(GAIM_CONV_CHAT(conv),
223 gaim_account_get_username(account));
224 }
225
226 gaim_conv_chat_clear_users(GAIM_CONV_CHAT(conv));
227 gaim_conv_chat_set_topic(GAIM_CONV_CHAT(conv), NULL, NULL);
228 GAIM_CONV_CHAT(conv)->left = FALSE;
229
230 gaim_conversation_update(conv, GAIM_CONV_UPDATE_CHATLEFT);
231 }
232
233 GaimConversation *
234 gaim_conversation_new(GaimConversationType type, GaimAccount *account,
235 const char *name)
236 {
237 GaimConversation *conv;
238 GaimConnection *gc;
239 GaimConversationUiOps *ops;
240
241 g_return_val_if_fail(type != GAIM_CONV_TYPE_UNKNOWN, NULL);
242 g_return_val_if_fail(account != NULL, NULL);
243 g_return_val_if_fail(name != NULL, NULL);
244
245 /* Check if this conversation already exists. */
246 if ((conv = gaim_find_conversation_with_account(type, name, account)) != NULL)
247 {
248 if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT ||
249 gaim_conv_chat_has_left(GAIM_CONV_CHAT(conv)))
250 {
251 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
252 gaim_conversation_chat_cleanup_for_rejoin(conv);
253
254 return conv;
255 }
256 }
257
258 gc = gaim_account_get_connection(account);
259 g_return_val_if_fail(gc != NULL, NULL);
260
261 conv = g_new0(GaimConversation, 1);
262 GAIM_DBUS_REGISTER_POINTER(conv, GaimConversation);
263
264 conv->type = type;
265 conv->account = account;
266 conv->name = g_strdup(name);
267 conv->title = g_strdup(name);
268 conv->data = g_hash_table_new_full(g_str_hash, g_str_equal,
269 g_free, NULL);
270 /* copy features from the connection. */
271 conv->features = gc->flags;
272
273 if (type == GAIM_CONV_TYPE_IM)
274 {
275 GaimBuddyIcon *icon;
276 conv->u.im = g_new0(GaimConvIm, 1);
277 conv->u.im->conv = conv;
278 GAIM_DBUS_REGISTER_POINTER(conv->u.im, GaimConvIm);
279
280 ims = g_list_append(ims, conv);
281 if ((icon = gaim_buddy_icons_find(account, name)))
282 gaim_conv_im_set_icon(conv->u.im, icon);
283
284 if (gaim_prefs_get_bool("/core/logging/log_ims"))
285 {
286 gaim_conversation_set_logging(conv, TRUE);
287 open_log(conv);
288 }
289 }
290 else if (type == GAIM_CONV_TYPE_CHAT)
291 {
292 const char *disp;
293
294 conv->u.chat = g_new0(GaimConvChat, 1);
295 conv->u.chat->conv = conv;
296 GAIM_DBUS_REGISTER_POINTER(conv->u.chat, GaimConvChat);
297
298 chats = g_list_append(chats, conv);
299
300 if ((disp = gaim_connection_get_display_name(account->gc)))
301 gaim_conv_chat_set_nick(conv->u.chat, disp);
302 else
303 gaim_conv_chat_set_nick(conv->u.chat,
304 gaim_account_get_username(account));
305
306 if (gaim_prefs_get_bool("/core/logging/log_chats"))
307 {
308 gaim_conversation_set_logging(conv, TRUE);
309 open_log(conv);
310 }
311 }
312
313 conversations = g_list_append(conversations, conv);
314
315 /* Auto-set the title. */
316 gaim_conversation_autoset_title(conv);
317
318 /* Don't move this.. it needs to be one of the last things done otherwise
319 * it causes mysterious crashes on my system.
320 * -- Gary
321 */
322 ops = conv->ui_ops = default_ops;
323 if (ops != NULL && ops->create_conversation != NULL)
324 ops->create_conversation(conv);
325
326 gaim_signal_emit(gaim_conversations_get_handle(),
327 "conversation-created", conv);
328
329 return conv;
330 }
331
332 void
333 gaim_conversation_destroy(GaimConversation *conv)
334 {
335 GaimPluginProtocolInfo *prpl_info = NULL;
336 GaimConversationUiOps *ops;
337 GaimConnection *gc;
338 const char *name;
339
340 g_return_if_fail(conv != NULL);
341
342 gaim_request_close_with_handle(conv);
343
344 ops = gaim_conversation_get_ui_ops(conv);
345 gc = gaim_conversation_get_gc(conv);
346 name = gaim_conversation_get_name(conv);
347
348 if (gc != NULL)
349 {
350 /* Still connected */
351 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
352
353 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM)
354 {
355 if (gaim_prefs_get_bool("/core/conversations/im/send_typing"))
356 serv_send_typing(gc, name, GAIM_NOT_TYPING);
357
358 if (gc && prpl_info->convo_closed != NULL)
359 prpl_info->convo_closed(gc, name);
360 }
361 else if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT)
362 {
363 int chat_id = gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv));
364 #if 0
365 /*
366 * This is unfortunately necessary, because calling
367 * serv_chat_leave() calls this gaim_conversation_destroy(),
368 * which leads to two calls here.. We can't just return after
369 * this, because then it'll return on the next pass. So, since
370 * serv_got_chat_left(), which is eventually called from the
371 * prpl that serv_chat_leave() calls, removes this conversation
372 * from the gc's buddy_chats list, we're going to check to see
373 * if this exists in the list. If so, we want to return after
374 * calling this, because it'll be called again. If not, fall
375 * through, because it'll have already been removed, and we'd
376 * be on the 2nd pass.
377 *
378 * Long paragraph. <-- Short sentence.
379 *
380 * -- ChipX86
381 */
382
383 if (gc && g_slist_find(gc->buddy_chats, conv) != NULL) {
384 serv_chat_leave(gc, chat_id);
385
386 return;
387 }
388 #endif
389 /*
390 * Instead of all of that, lets just close the window when
391 * the user tells us to, and let the prpl deal with the
392 * internals on it's own time. Don't do this if the prpl already
393 * knows it left the chat.
394 */
395 if (!gaim_conv_chat_has_left(GAIM_CONV_CHAT(conv)))
396 serv_chat_leave(gc, chat_id);
397
398 /*
399 * If they didn't call serv_got_chat_left by now, it's too late.
400 * So we better do it for them before we destroy the thing.
401 */
402 if (!gaim_conv_chat_has_left(GAIM_CONV_CHAT(conv)))
403 serv_got_chat_left(gc, chat_id);
404 }
405 }
406
407 /* remove from conversations and im/chats lists prior to emit */
408 conversations = g_list_remove(conversations, conv);
409
410 if(conv->type==GAIM_CONV_TYPE_IM)
411 ims = g_list_remove(ims, conv);
412 else if(conv->type==GAIM_CONV_TYPE_CHAT)
413 chats = g_list_remove(chats, conv);
414
415 gaim_signal_emit(gaim_conversations_get_handle(),
416 "deleting-conversation", conv);
417
418 g_free(conv->name);
419 g_free(conv->title);
420
421 conv->name = NULL;
422 conv->title = NULL;
423
424 if (conv->type == GAIM_CONV_TYPE_IM) {
425 gaim_conv_im_stop_typing_timeout(conv->u.im);
426 gaim_conv_im_stop_send_typed_timeout(conv->u.im);
427
428 if (conv->u.im->icon != NULL)
429 gaim_buddy_icon_unref(conv->u.im->icon);
430 conv->u.im->icon = NULL;
431
432 GAIM_DBUS_UNREGISTER_POINTER(conv->u.im);
433 g_free(conv->u.im);
434 conv->u.im = NULL;
435 }
436 else if (conv->type == GAIM_CONV_TYPE_CHAT) {
437
438 g_list_foreach(conv->u.chat->in_room, (GFunc)gaim_conv_chat_cb_destroy, NULL);
439 g_list_free(conv->u.chat->in_room);
440
441 g_list_foreach(conv->u.chat->ignored, (GFunc)g_free, NULL);
442 g_list_free(conv->u.chat->ignored);
443
444 conv->u.chat->in_room = NULL;
445 conv->u.chat->ignored = NULL;
446
447 g_free(conv->u.chat->who);
448 conv->u.chat->who = NULL;
449
450 g_free(conv->u.chat->topic);
451 conv->u.chat->topic = NULL;
452
453 g_free(conv->u.chat->nick);
454
455 GAIM_DBUS_UNREGISTER_POINTER(conv->u.chat);
456 g_free(conv->u.chat);
457 conv->u.chat = NULL;
458 }
459
460 g_hash_table_destroy(conv->data);
461 conv->data = NULL;
462
463 if (ops != NULL && ops->destroy_conversation != NULL)
464 ops->destroy_conversation(conv);
465
466 gaim_conversation_close_logs(conv);
467
468 GAIM_DBUS_UNREGISTER_POINTER(conv);
469 g_free(conv);
470 conv = NULL;
471 }
472
473
474 void
475 gaim_conversation_present(GaimConversation *conv) {
476 GaimConversationUiOps *ops;
477
478 g_return_if_fail(conv != NULL);
479
480 ops = gaim_conversation_get_ui_ops(conv);
481 if(ops && ops->present)
482 ops->present(conv);
483 }
484
485
486 void
487 gaim_conversation_set_features(GaimConversation *conv, GaimConnectionFlags features)
488 {
489 g_return_if_fail(conv != NULL);
490
491 conv->features = features;
492
493 gaim_conversation_update(conv, GAIM_CONV_UPDATE_FEATURES);
494 }
495
496
497 GaimConnectionFlags
498 gaim_conversation_get_features(GaimConversation *conv)
499 {
500 g_return_val_if_fail(conv != NULL, 0);
501 return conv->features;
502 }
503
504
505 GaimConversationType
506 gaim_conversation_get_type(const GaimConversation *conv)
507 {
508 g_return_val_if_fail(conv != NULL, GAIM_CONV_TYPE_UNKNOWN);
509
510 return conv->type;
511 }
512
513 void
514 gaim_conversation_set_ui_ops(GaimConversation *conv,
515 GaimConversationUiOps *ops)
516 {
517 g_return_if_fail(conv != NULL);
518
519 if (conv->ui_ops == ops)
520 return;
521
522 if (conv->ui_ops != NULL && conv->ui_ops->destroy_conversation != NULL)
523 conv->ui_ops->destroy_conversation(conv);
524
525 conv->ui_data = NULL;
526
527 conv->ui_ops = ops;
528 }
529
530 GaimConversationUiOps *
531 gaim_conversation_get_ui_ops(const GaimConversation *conv)
532 {
533 g_return_val_if_fail(conv != NULL, NULL);
534
535 return conv->ui_ops;
536 }
537
538 void
539 gaim_conversation_set_account(GaimConversation *conv, GaimAccount *account)
540 {
541 g_return_if_fail(conv != NULL);
542
543 if (account == gaim_conversation_get_account(conv))
544 return;
545
546 conv->account = account;
547
548 gaim_conversation_update(conv, GAIM_CONV_UPDATE_ACCOUNT);
549 }
550
551 GaimAccount *
552 gaim_conversation_get_account(const GaimConversation *conv)
553 {
554 g_return_val_if_fail(conv != NULL, NULL);
555
556 return conv->account;
557 }
558
559 GaimConnection *
560 gaim_conversation_get_gc(const GaimConversation *conv)
561 {
562 GaimAccount *account;
563
564 g_return_val_if_fail(conv != NULL, NULL);
565
566 account = gaim_conversation_get_account(conv);
567
568 if (account == NULL)
569 return NULL;
570
571 return account->gc;
572 }
573
574 void
575 gaim_conversation_set_title(GaimConversation *conv, const char *title)
576 {
577 g_return_if_fail(conv != NULL);
578 g_return_if_fail(title != NULL);
579
580 g_free(conv->title);
581 conv->title = g_strdup(title);
582
583 gaim_conversation_update(conv, GAIM_CONV_UPDATE_TITLE);
584 }
585
586 const char *
587 gaim_conversation_get_title(const GaimConversation *conv)
588 {
589 g_return_val_if_fail(conv != NULL, NULL);
590
591 return conv->title;
592 }
593
594 void
595 gaim_conversation_autoset_title(GaimConversation *conv)
596 {
597 GaimAccount *account;
598 GaimBuddy *b;
599 GaimChat *chat;
600 const char *text = NULL, *name;
601
602 g_return_if_fail(conv != NULL);
603
604 account = gaim_conversation_get_account(conv);
605 name = gaim_conversation_get_name(conv);
606
607 if(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
608 if(account && ((b = gaim_find_buddy(account, name)) != NULL))
609 text = gaim_buddy_get_contact_alias(b);
610 } else if(gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) {
611 if(account && ((chat = gaim_blist_find_chat(account, name)) != NULL))
612 text = chat->alias;
613 }
614
615
616 if(text == NULL)
617 text = name;
618
619 gaim_conversation_set_title(conv, text);
620 }
621
622 void
623 gaim_conversation_foreach(void (*func)(GaimConversation *conv))
624 {
625 GaimConversation *conv;
626 GList *l;
627
628 g_return_if_fail(func != NULL);
629
630 for (l = gaim_get_conversations(); l != NULL; l = l->next) {
631 conv = (GaimConversation *)l->data;
632
633 func(conv);
634 }
635 }
636
637 void
638 gaim_conversation_set_name(GaimConversation *conv, const char *name)
639 {
640 g_return_if_fail(conv != NULL);
641
642 g_free(conv->name);
643 conv->name = g_strdup(name);
644
645 gaim_conversation_autoset_title(conv);
646 }
647
648 const char *
649 gaim_conversation_get_name(const GaimConversation *conv)
650 {
651 g_return_val_if_fail(conv != NULL, NULL);
652
653 return conv->name;
654 }
655
656 void
657 gaim_conversation_set_logging(GaimConversation *conv, gboolean log)
658 {
659 g_return_if_fail(conv != NULL);
660
661 if (conv->logging != log)
662 {
663 conv->logging = log;
664 gaim_conversation_update(conv, GAIM_CONV_UPDATE_LOGGING);
665 }
666 }
667
668 gboolean
669 gaim_conversation_is_logging(const GaimConversation *conv)
670 {
671 g_return_val_if_fail(conv != NULL, FALSE);
672
673 return conv->logging;
674 }
675
676 void
677 gaim_conversation_close_logs(GaimConversation *conv)
678 {
679 g_return_if_fail(conv != NULL);
680
681 g_list_foreach(conv->logs, (GFunc)gaim_log_free, NULL);
682 g_list_free(conv->logs);
683 conv->logs = NULL;
684 }
685
686 GaimConvIm *
687 gaim_conversation_get_im_data(const GaimConversation *conv)
688 {
689 g_return_val_if_fail(conv != NULL, NULL);
690
691 if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_IM)
692 return NULL;
693
694 return conv->u.im;
695 }
696
697 GaimConvChat *
698 gaim_conversation_get_chat_data(const GaimConversation *conv)
699 {
700 g_return_val_if_fail(conv != NULL, NULL);
701
702 if (gaim_conversation_get_type(conv) != GAIM_CONV_TYPE_CHAT)
703 return NULL;
704
705 return conv->u.chat;
706 }
707
708 void
709 gaim_conversation_set_data(GaimConversation *conv, const char *key,
710 gpointer data)
711 {
712 g_return_if_fail(conv != NULL);
713 g_return_if_fail(key != NULL);
714
715 g_hash_table_replace(conv->data, g_strdup(key), data);
716 }
717
718 gpointer
719 gaim_conversation_get_data(GaimConversation *conv, const char *key)
720 {
721 g_return_val_if_fail(conv != NULL, NULL);
722 g_return_val_if_fail(key != NULL, NULL);
723
724 return g_hash_table_lookup(conv->data, key);
725 }
726
727 GList *
728 gaim_get_conversations(void)
729 {
730 return conversations;
731 }
732
733 GList *
734 gaim_get_ims(void)
735 {
736 return ims;
737 }
738
739 GList *
740 gaim_get_chats(void)
741 {
742 return chats;
743 }
744
745
746 GaimConversation *
747 gaim_find_conversation_with_account(GaimConversationType type,
748 const char *name,
749 const GaimAccount *account)
750 {
751 GaimConversation *c = NULL;
752 gchar *name1;
753 const gchar *name2;
754 GList *cnv;
755
756 g_return_val_if_fail(name != NULL, NULL);
757
758 name1 = g_strdup(gaim_normalize(account, name));
759
760 for (cnv = gaim_get_conversations(); cnv != NULL; cnv = cnv->next) {
761 c = (GaimConversation *)cnv->data;
762 name2 = gaim_normalize(account, gaim_conversation_get_name(c));
763
764 if (((type == GAIM_CONV_TYPE_ANY) || (type == gaim_conversation_get_type(c))) &&
765 (account == gaim_conversation_get_account(c)) &&
766 !gaim_utf8_strcasecmp(name1, name2)) {
767
768 break;
769 }
770
771 c = NULL;
772 }
773
774 g_free(name1);
775
776 return c;
777 }
778
779 void
780 gaim_conversation_write(GaimConversation *conv, const char *who,
781 const char *message, GaimMessageFlags flags,
782 time_t mtime)
783 {
784 GaimPluginProtocolInfo *prpl_info = NULL;
785 GaimConnection *gc = NULL;
786 GaimAccount *account;
787 GaimConversationUiOps *ops;
788 const char *alias;
789 char *displayed = NULL;
790 GaimBuddy *b;
791 int plugin_return;
792 GaimConversationType type;
793 /* int logging_font_options = 0; */
794
795 g_return_if_fail(conv != NULL);
796 g_return_if_fail(message != NULL);
797
798 ops = gaim_conversation_get_ui_ops(conv);
799
800 if (ops == NULL || ops->write_conv == NULL)
801 return;
802
803 account = gaim_conversation_get_account(conv);
804 type = gaim_conversation_get_type(conv);
805
806 if (account != NULL)
807 gc = gaim_account_get_connection(account);
808
809 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT &&
810 (gc == NULL || !g_slist_find(gc->buddy_chats, conv)))
811 return;
812
813 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM &&
814 !g_list_find(gaim_get_conversations(), conv))
815 return;
816
817 displayed = g_strdup(message);
818
819 plugin_return =
820 GPOINTER_TO_INT(gaim_signal_emit_return_1(
821 gaim_conversations_get_handle(),
822 (type == GAIM_CONV_TYPE_IM ? "writing-im-msg" : "writing-chat-msg"),
823 account, who, &displayed, conv, flags));
824
825 if (displayed == NULL)
826 return;
827
828 if (plugin_return) {
829 g_free(displayed);
830 return;
831 }
832
833 if (who == NULL || *who == '\0')
834 who = gaim_conversation_get_name(conv);
835
836 alias = who;
837
838 if (account != NULL) {
839 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gaim_find_prpl(gaim_account_get_protocol_id(account)));
840
841 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM ||
842 !(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
843
844 if (flags & GAIM_MESSAGE_SEND) {
845 b = gaim_find_buddy(account,
846 gaim_account_get_username(account));
847
848 if (gaim_account_get_alias(account) != NULL)
849 alias = account->alias;
850 else if (b != NULL && strcmp(b->name, gaim_buddy_get_contact_alias(b)))
851 alias = gaim_buddy_get_contact_alias(b);
852 else if (gaim_connection_get_display_name(gc) != NULL)
853 alias = gaim_connection_get_display_name(gc);
854 else
855 alias = gaim_account_get_username(account);
856 }
857 else
858 {
859 b = gaim_find_buddy(account, who);
860
861 if (b != NULL)
862 alias = gaim_buddy_get_contact_alias(b);
863 }
864 }
865 }
866
867 if (!(flags & GAIM_MESSAGE_NO_LOG) && gaim_conversation_is_logging(conv)) {
868 GList *log;
869
870 if (conv->logs == NULL)
871 open_log(conv);
872
873 log = conv->logs;
874 while (log != NULL) {
875 gaim_log_write((GaimLog *)log->data, flags, alias, mtime, displayed);
876 log = log->next;
877 }
878 }
879
880 if (gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) {
881 if ((flags & GAIM_MESSAGE_RECV) == GAIM_MESSAGE_RECV) {
882 gaim_conv_im_set_typing_state(GAIM_CONV_IM(conv), GAIM_NOT_TYPING);
883 }
884 }
885
886 ops->write_conv(conv, who, alias, displayed, flags, mtime);
887
888 gaim_signal_emit(gaim_conversations_get_handle(),
889 (type == GAIM_CONV_TYPE_IM ? "wrote-im-msg" : "wrote-chat-msg"),
890 account, who, displayed, conv, flags);
891
892 g_free(displayed);
893 }
894
895 gboolean
896 gaim_conversation_has_focus(GaimConversation *conv)
897 {
898 gboolean ret = FALSE;
899 GaimConversationUiOps *ops;
900
901 g_return_val_if_fail(conv != NULL, FALSE);
902
903 ops = gaim_conversation_get_ui_ops(conv);
904
905 if (ops != NULL && ops->has_focus != NULL)
906 ret = ops->has_focus(conv);
907
908 return ret;
909 }
910
911 /*
912 * TODO: Need to make sure calls to this function happen in the core
913 * instead of the UI. That way UIs have less work to do, and the
914 * core/UI split is cleaner. Also need to make sure this is called
915 * when chats are added/removed from the blist.
916 */
917 void
918 gaim_conversation_update(GaimConversation *conv, GaimConvUpdateType type)
919 {
920 g_return_if_fail(conv != NULL);
921
922 gaim_signal_emit(gaim_conversations_get_handle(),
923 "conversation-updated", conv, type);
924 }
925
926 /**************************************************************************
927 * IM Conversation API
928 **************************************************************************/
929 GaimConversation *
930 gaim_conv_im_get_conversation(const GaimConvIm *im)
931 {
932 g_return_val_if_fail(im != NULL, NULL);
933
934 return im->conv;
935 }
936
937 void
938 gaim_conv_im_set_icon(GaimConvIm *im, GaimBuddyIcon *icon)
939 {
940 g_return_if_fail(im != NULL);
941
942 if (im->icon != icon)
943 {
944 if (im->icon != NULL)
945 gaim_buddy_icon_unref(im->icon);
946
947 im->icon = (icon == NULL ? NULL : gaim_buddy_icon_ref(icon));
948 }
949
950 gaim_conversation_update(gaim_conv_im_get_conversation(im),
951 GAIM_CONV_UPDATE_ICON);
952 }
953
954 GaimBuddyIcon *
955 gaim_conv_im_get_icon(const GaimConvIm *im)
956 {
957 g_return_val_if_fail(im != NULL, NULL);
958
959 return im->icon;
960 }
961
962 void
963 gaim_conv_im_set_typing_state(GaimConvIm *im, GaimTypingState state)
964 {
965 g_return_if_fail(im != NULL);
966
967 if (im->typing_state != state)
968 {
969 im->typing_state = state;
970
971 if (state == GAIM_TYPING)
972 {
973 gaim_signal_emit(gaim_conversations_get_handle(),
974 "buddy-typing", im->conv->account, im->conv->name);
975 }
976 else if (state == GAIM_TYPED)
977 {
978 gaim_signal_emit(gaim_conversations_get_handle(),
979 "buddy-typed", im->conv->account, im->conv->name);
980 }
981 else if (state == GAIM_NOT_TYPING)
982 {
983 gaim_signal_emit(gaim_conversations_get_handle(),
984 "buddy-typing-stopped", im->conv->account, im->conv->name);
985 }
986 }
987 }
988
989 GaimTypingState
990 gaim_conv_im_get_typing_state(const GaimConvIm *im)
991 {
992 g_return_val_if_fail(im != NULL, 0);
993
994 return im->typing_state;
995 }
996
997 void
998 gaim_conv_im_start_typing_timeout(GaimConvIm *im, int timeout)
999 {
1000 GaimConversation *conv;
1001 const char *name;
1002
1003 g_return_if_fail(im != NULL);
1004
1005 if (im->typing_timeout > 0)
1006 gaim_conv_im_stop_typing_timeout(im);
1007
1008 conv = gaim_conv_im_get_conversation(im);
1009 name = gaim_conversation_get_name(conv);
1010
1011 im->typing_timeout = gaim_timeout_add(timeout * 1000, reset_typing_cb, conv);
1012 }
1013
1014 void
1015 gaim_conv_im_stop_typing_timeout(GaimConvIm *im)
1016 {
1017 g_return_if_fail(im != NULL);
1018
1019 if (im->typing_timeout == 0)
1020 return;
1021
1022 gaim_timeout_remove(im->typing_timeout);
1023 im->typing_timeout = 0;
1024 }
1025
1026 guint
1027 gaim_conv_im_get_typing_timeout(const GaimConvIm *im)
1028 {
1029 g_return_val_if_fail(im != NULL, 0);
1030
1031 return im->typing_timeout;
1032 }
1033
1034 void
1035 gaim_conv_im_set_type_again(GaimConvIm *im, unsigned int val)
1036 {
1037 g_return_if_fail(im != NULL);
1038
1039 if (val == 0)
1040 im->type_again = 0;
1041 else
1042 im->type_again = time(NULL) + val;
1043 }
1044
1045 time_t
1046 gaim_conv_im_get_type_again(const GaimConvIm *im)
1047 {
1048 g_return_val_if_fail(im != NULL, 0);
1049
1050 return im->type_again;
1051 }
1052
1053 void
1054 gaim_conv_im_start_send_typed_timeout(GaimConvIm *im)
1055 {
1056 g_return_if_fail(im != NULL);
1057
1058 im->send_typed_timeout = gaim_timeout_add(SEND_TYPED_TIMEOUT, send_typed_cb,
1059 gaim_conv_im_get_conversation(im));
1060 }
1061
1062 void
1063 gaim_conv_im_stop_send_typed_timeout(GaimConvIm *im)
1064 {
1065 g_return_if_fail(im != NULL);
1066
1067 if (im->send_typed_timeout == 0)
1068 return;
1069
1070 gaim_timeout_remove(im->send_typed_timeout);
1071 im->send_typed_timeout = 0;
1072 }
1073
1074 guint
1075 gaim_conv_im_get_send_typed_timeout(const GaimConvIm *im)
1076 {
1077 g_return_val_if_fail(im != NULL, 0);
1078
1079 return im->send_typed_timeout;
1080 }
1081
1082 void
1083 gaim_conv_im_update_typing(GaimConvIm *im)
1084 {
1085 g_return_if_fail(im != NULL);
1086
1087 gaim_conversation_update(gaim_conv_im_get_conversation(im),
1088 GAIM_CONV_UPDATE_TYPING);
1089 }
1090
1091 void
1092 gaim_conv_im_write(GaimConvIm *im, const char *who, const char *message,
1093 GaimMessageFlags flags, time_t mtime)
1094 {
1095 GaimConversation *c;
1096
1097 g_return_if_fail(im != NULL);
1098 g_return_if_fail(message != NULL);
1099
1100 c = gaim_conv_im_get_conversation(im);
1101
1102 /* Raise the window, if specified in prefs. */
1103 if (c->ui_ops != NULL && c->ui_ops->write_im != NULL)
1104 c->ui_ops->write_im(c, who, message, flags, mtime);
1105 else
1106 gaim_conversation_write(c, who, message, flags, mtime);
1107 }
1108
1109 gboolean gaim_conv_present_error(const char *who, GaimAccount *account, const char *what)
1110 {
1111 GaimConversation *conv;
1112
1113 g_return_val_if_fail(who != NULL, FALSE);
1114 g_return_val_if_fail(account !=NULL, FALSE);
1115 g_return_val_if_fail(what != NULL, FALSE);
1116
1117 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_ANY, who, account);
1118 if (conv != NULL)
1119 gaim_conversation_write(conv, NULL, what, GAIM_MESSAGE_ERROR, time(NULL));
1120 else
1121 return FALSE;
1122
1123 return TRUE;
1124 }
1125
1126 void
1127 gaim_conv_im_send(GaimConvIm *im, const char *message)
1128 {
1129 gaim_conv_im_send_with_flags(im, message, 0);
1130 }
1131
1132 static void
1133 gaim_conv_send_confirm_cb(gpointer *data)
1134 {
1135 GaimConversation *conv = data[0];
1136 char *message = data[1];
1137
1138 g_free(data);
1139 common_send(conv, message, 0);
1140 }
1141
1142 void
1143 gaim_conv_send_confirm(GaimConversation *conv, const char *message)
1144 {
1145 char *text;
1146 gpointer *data;
1147
1148 g_return_if_fail(conv != NULL);
1149 g_return_if_fail(message != NULL);
1150
1151 if (conv->ui_ops != NULL && conv->ui_ops->send_confirm != NULL)
1152 {
1153 conv->ui_ops->send_confirm(conv, message);
1154 return;
1155 }
1156
1157 text = g_strdup_printf("You are about to send the following message:\n%s", message);
1158 data = g_new0(gpointer, 2);
1159 data[0] = conv;
1160 data[1] = (gpointer)message;
1161
1162 gaim_request_action(conv, NULL, _("Send Message"), text, 0, data, 2,
1163 _("_Send Message"), G_CALLBACK(gaim_conv_send_confirm_cb),
1164 _("Cancel"), NULL);
1165 }
1166
1167 void
1168 gaim_conv_im_send_with_flags(GaimConvIm *im, const char *message, GaimMessageFlags flags)
1169 {
1170 g_return_if_fail(im != NULL);
1171 g_return_if_fail(message != NULL);
1172
1173 common_send(gaim_conv_im_get_conversation(im), message, flags);
1174 }
1175
1176 gboolean
1177 gaim_conv_custom_smiley_add(GaimConversation *conv, const char *smile,
1178 const char *cksum_type, const char *chksum,
1179 gboolean remote)
1180 {
1181 if (conv == NULL || smile == NULL || !*smile) {
1182 return FALSE;
1183 }
1184
1185 /* TODO: check if the icon is in the cache and return false if so */
1186 /* TODO: add an icon cache (that doesn't suck) */
1187 if (conv->ui_ops != NULL && conv->ui_ops->custom_smiley_add !=NULL) {
1188 return conv->ui_ops->custom_smiley_add(conv, smile, remote);
1189 } else {
1190 gaim_debug_info("conversation", "Could not find add custom smiley function");
1191 return FALSE;
1192 }
1193
1194 }
1195
1196 void
1197 gaim_conv_custom_smiley_write(GaimConversation *conv, const char *smile,
1198 const guchar *data, gsize size)
1199 {
1200 g_return_if_fail(conv != NULL);
1201 g_return_if_fail(smile != NULL && *smile);
1202
1203 if (conv->ui_ops != NULL && conv->ui_ops->custom_smiley_write != NULL)
1204 conv->ui_ops->custom_smiley_write(conv, smile, data, size);
1205 else
1206 gaim_debug_info("conversation", "Could not find the smiley write function");
1207 }
1208
1209 void
1210 gaim_conv_custom_smiley_close(GaimConversation *conv, const char *smile)
1211 {
1212 g_return_if_fail(conv != NULL);
1213 g_return_if_fail(smile != NULL && *smile);
1214
1215 if (conv->ui_ops != NULL && conv->ui_ops->custom_smiley_close != NULL)
1216 conv->ui_ops->custom_smiley_close(conv, smile);
1217 else
1218 gaim_debug_info("conversation", "Could not find custom smiley close function");
1219 }
1220
1221
1222 /**************************************************************************
1223 * Chat Conversation API
1224 **************************************************************************/
1225
1226 GaimConversation *
1227 gaim_conv_chat_get_conversation(const GaimConvChat *chat)
1228 {
1229 g_return_val_if_fail(chat != NULL, NULL);
1230
1231 return chat->conv;
1232 }
1233
1234 GList *
1235 gaim_conv_chat_set_users(GaimConvChat *chat, GList *users)
1236 {
1237 g_return_val_if_fail(chat != NULL, NULL);
1238
1239 chat->in_room = users;
1240
1241 return users;
1242 }
1243
1244 GList *
1245 gaim_conv_chat_get_users(const GaimConvChat *chat)
1246 {
1247 g_return_val_if_fail(chat != NULL, NULL);
1248
1249 return chat->in_room;
1250 }
1251
1252 void
1253 gaim_conv_chat_ignore(GaimConvChat *chat, const char *name)
1254 {
1255 g_return_if_fail(chat != NULL);
1256 g_return_if_fail(name != NULL);
1257
1258 /* Make sure the user isn't already ignored. */
1259 if (gaim_conv_chat_is_user_ignored(chat, name))
1260 return;
1261
1262 gaim_conv_chat_set_ignored(chat,
1263 g_list_append(gaim_conv_chat_get_ignored(chat), g_strdup(name)));
1264 }
1265
1266 void
1267 gaim_conv_chat_unignore(GaimConvChat *chat, const char *name)
1268 {
1269 GList *item;
1270
1271 g_return_if_fail(chat != NULL);
1272 g_return_if_fail(name != NULL);
1273
1274 /* Make sure the user is actually ignored. */
1275 if (!gaim_conv_chat_is_user_ignored(chat, name))
1276 return;
1277
1278 item = g_list_find(gaim_conv_chat_get_ignored(chat),
1279 gaim_conv_chat_get_ignored_user(chat, name));
1280
1281 gaim_conv_chat_set_ignored(chat,
1282 g_list_remove_link(gaim_conv_chat_get_ignored(chat), item));
1283
1284 g_free(item->data);
1285 g_list_free_1(item);
1286 }
1287
1288 GList *
1289 gaim_conv_chat_set_ignored(GaimConvChat *chat, GList *ignored)
1290 {
1291 g_return_val_if_fail(chat != NULL, NULL);
1292
1293 chat->ignored = ignored;
1294
1295 return ignored;
1296 }
1297
1298 GList *
1299 gaim_conv_chat_get_ignored(const GaimConvChat *chat)
1300 {
1301 g_return_val_if_fail(chat != NULL, NULL);
1302
1303 return chat->ignored;
1304 }
1305
1306 const char *
1307 gaim_conv_chat_get_ignored_user(const GaimConvChat *chat, const char *user)
1308 {
1309 GList *ignored;
1310
1311 g_return_val_if_fail(chat != NULL, NULL);
1312 g_return_val_if_fail(user != NULL, NULL);
1313
1314 for (ignored = gaim_conv_chat_get_ignored(chat);
1315 ignored != NULL;
1316 ignored = ignored->next) {
1317
1318 const char *ign = (const char *)ignored->data;
1319
1320 if (!gaim_utf8_strcasecmp(user, ign) ||
1321 ((*ign == '+' || *ign == '%') && !gaim_utf8_strcasecmp(user, ign + 1)))
1322 return ign;
1323
1324 if (*ign == '@') {
1325 ign++;
1326
1327 if ((*ign == '+' && !gaim_utf8_strcasecmp(user, ign + 1)) ||
1328 (*ign != '+' && !gaim_utf8_strcasecmp(user, ign)))
1329 return ign;
1330 }
1331 }
1332
1333 return NULL;
1334 }
1335
1336 gboolean
1337 gaim_conv_chat_is_user_ignored(const GaimConvChat *chat, const char *user)
1338 {
1339 g_return_val_if_fail(chat != NULL, FALSE);
1340 g_return_val_if_fail(user != NULL, FALSE);
1341
1342 return (gaim_conv_chat_get_ignored_user(chat, user) != NULL);
1343 }
1344
1345 void
1346 gaim_conv_chat_set_topic(GaimConvChat *chat, const char *who, const char *topic)
1347 {
1348 g_return_if_fail(chat != NULL);
1349
1350 g_free(chat->who);
1351 g_free(chat->topic);
1352
1353 chat->who = g_strdup(who);
1354 chat->topic = g_strdup(topic);
1355
1356 gaim_conversation_update(gaim_conv_chat_get_conversation(chat),
1357 GAIM_CONV_UPDATE_TOPIC);
1358
1359 gaim_signal_emit(gaim_conversations_get_handle(), "chat-topic-changed",
1360 chat->conv, chat->who, chat->topic);
1361 }
1362
1363 const char *
1364 gaim_conv_chat_get_topic(const GaimConvChat *chat)
1365 {
1366 g_return_val_if_fail(chat != NULL, NULL);
1367
1368 return chat->topic;
1369 }
1370
1371 void
1372 gaim_conv_chat_set_id(GaimConvChat *chat, int id)
1373 {
1374 g_return_if_fail(chat != NULL);
1375
1376 chat->id = id;
1377 }
1378
1379 int
1380 gaim_conv_chat_get_id(const GaimConvChat *chat)
1381 {
1382 g_return_val_if_fail(chat != NULL, -1);
1383
1384 return chat->id;
1385 }
1386
1387 void
1388 gaim_conv_chat_write(GaimConvChat *chat, const char *who, const char *message,
1389 GaimMessageFlags flags, time_t mtime)
1390 {
1391 GaimAccount *account;
1392 GaimConversation *conv;
1393 GaimConnection *gc;
1394 GaimPluginProtocolInfo *prpl_info;
1395
1396 g_return_if_fail(chat != NULL);
1397 g_return_if_fail(who != NULL);
1398 g_return_if_fail(message != NULL);
1399
1400 conv = gaim_conv_chat_get_conversation(chat);
1401 gc = gaim_conversation_get_gc(conv);
1402 account = gaim_connection_get_account(gc);
1403 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
1404
1405 /* Don't display this if the person who wrote it is ignored. */
1406 if (gaim_conv_chat_is_user_ignored(chat, who))
1407 return;
1408
1409 if (!(flags & GAIM_MESSAGE_WHISPER)) {
1410 char *str;
1411
1412 str = g_strdup(gaim_normalize(account, who));
1413
1414 if (!strcmp(str, gaim_normalize(account, chat->nick))) {
1415 flags |= GAIM_MESSAGE_SEND;
1416 } else {
1417 flags |= GAIM_MESSAGE_RECV;
1418
1419 if (gaim_utf8_has_word(message, chat->nick))
1420 flags |= GAIM_MESSAGE_NICK;
1421 }
1422
1423 g_free(str);
1424 }
1425
1426 /* Pass this on to either the ops structure or the default write func. */
1427 if (conv->ui_ops != NULL && conv->ui_ops->write_chat != NULL)
1428 conv->ui_ops->write_chat(conv, who, message, flags, mtime);
1429 else
1430 gaim_conversation_write(conv, who, message, flags, mtime);
1431 }
1432
1433 void
1434 gaim_conv_chat_send(GaimConvChat *chat, const char *message)
1435 {
1436 gaim_conv_chat_send_with_flags(chat, message, 0);
1437 }
1438
1439 void
1440 gaim_conv_chat_send_with_flags(GaimConvChat *chat, const char *message, GaimMessageFlags flags)
1441 {
1442 g_return_if_fail(chat != NULL);
1443 g_return_if_fail(message != NULL);
1444
1445 common_send(gaim_conv_chat_get_conversation(chat), message, flags);
1446 }
1447
1448 void
1449 gaim_conv_chat_add_user(GaimConvChat *chat, const char *user,
1450 const char *extra_msg, GaimConvChatBuddyFlags flags,
1451 gboolean new_arrival)
1452 {
1453 GList *users = g_list_append(NULL, (char *)user);
1454 GList *extra_msgs = g_list_append(NULL, (char *)extra_msg);
1455 GList *flags2 = g_list_append(NULL, GINT_TO_POINTER(flags));
1456
1457 gaim_conv_chat_add_users(chat, users, extra_msgs, flags2, new_arrival);
1458
1459 g_list_free(users);
1460 g_list_free(extra_msgs);
1461 g_list_free(flags2);
1462 }
1463
1464 static int
1465 gaim_conv_chat_cb_compare(GaimConvChatBuddy *a, GaimConvChatBuddy *b)
1466 {
1467 GaimConvChatBuddyFlags f1 = 0, f2 = 0;
1468 char *user1 = NULL, *user2 = NULL;
1469 gint ret = 0;
1470
1471 if (a) {
1472 f1 = a->flags;
1473 if (a->alias_key)
1474 user1 = a->alias_key;
1475 else if (a->name)
1476 user1 = a->name;
1477 }
1478
1479 if (b) {
1480 f2 = b->flags;
1481 if (b->alias_key)
1482 user2 = b->alias_key;
1483 else if (b->name)
1484 user2 = b->name;
1485 }
1486
1487 if (user1 == NULL || user2 == NULL) {
1488 if (!(user1 == NULL && user2 == NULL))
1489 ret = (user1 == NULL) ? -1: 1;
1490 } else if (f1 != f2) {
1491 /* sort more important users first */
1492 ret = (f1 > f2) ? -1 : 1;
1493 } else if (a->buddy != b->buddy) {
1494 ret = a->buddy ? -1 : 1;
1495 } else {
1496 ret = strcasecmp(user1, user2);
1497 }
1498
1499 return ret;
1500 }
1501
1502 void
1503 gaim_conv_chat_add_users(GaimConvChat *chat, GList *users, GList *extra_msgs,
1504 GList *flags, gboolean new_arrivals)
1505 {
1506 GaimConversation *conv;
1507 GaimConversationUiOps *ops;
1508 GaimConvChatBuddy *cbuddy;
1509 GaimConnection *gc;
1510 GaimPluginProtocolInfo *prpl_info;
1511 GList *ul, *fl;
1512 GList *cbuddies = NULL;
1513
1514 g_return_if_fail(chat != NULL);
1515 g_return_if_fail(users != NULL);
1516
1517 conv = gaim_conv_chat_get_conversation(chat);
1518 ops = gaim_conversation_get_ui_ops(conv);
1519
1520 gc = gaim_conversation_get_gc(conv);
1521 g_return_if_fail(gc != NULL);
1522 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
1523 g_return_if_fail(prpl_info != NULL);
1524
1525 ul = users;
1526 fl = flags;
1527 while ((ul != NULL) && (fl != NULL)) {
1528 const char *user = (const char *)ul->data;
1529 const char *alias = user;
1530 gboolean quiet;
1531 GaimConvChatBuddyFlags flag = GPOINTER_TO_INT(fl->data);
1532 const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL);
1533
1534 if (!strcmp(chat->nick, gaim_normalize(conv->account, user))) {
1535 const char *alias2 = gaim_account_get_alias(conv->account);
1536 if (alias2 != NULL)
1537 alias = alias2;
1538 else
1539 {
1540 const char *display_name = gaim_connection_get_display_name(gc);
1541 if (display_name != NULL)
1542 alias = display_name;
1543 }
1544 } else if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
1545 GaimBuddy *buddy;
1546 if ((buddy = gaim_find_buddy(gc->account, user)) != NULL)
1547 alias = gaim_buddy_get_contact_alias(buddy);
1548 }
1549
1550 quiet = GPOINTER_TO_INT(gaim_signal_emit_return_1(gaim_conversations_get_handle(),
1551 "chat-buddy-joining", conv, user, flag)) |
1552 gaim_conv_chat_is_user_ignored(chat, user);
1553
1554 cbuddy = gaim_conv_chat_cb_new(user, alias, flag);
1555 /* This seems dumb. Why should we set users thousands of times? */
1556 gaim_conv_chat_set_users(chat,
1557 g_list_prepend(gaim_conv_chat_get_users(chat), cbuddy));
1558
1559 cbuddies = g_list_prepend(cbuddies, cbuddy);
1560
1561 if (!quiet && new_arrivals) {
1562 char *escaped = g_markup_escape_text(alias, -1);
1563 char *tmp;
1564
1565 if (extra_msg == NULL)
1566 tmp = g_strdup_printf(_("%s entered the room."), escaped);
1567 else {
1568 char *escaped2 = g_markup_escape_text(extra_msg, -1);
1569 tmp = g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
1570 escaped, escaped2);
1571 g_free(escaped2);
1572 }
1573 g_free(escaped);
1574
1575 gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
1576 g_free(tmp);
1577 }
1578
1579 gaim_signal_emit(gaim_conversations_get_handle(),
1580 "chat-buddy-joined", conv, user, flag, new_arrivals);
1581 ul = ul->next;
1582 fl = fl->next;
1583 if (extra_msgs != NULL)
1584 extra_msgs = extra_msgs->next;
1585 }
1586
1587 cbuddies = g_list_sort(cbuddies, (GCompareFunc)gaim_conv_chat_cb_compare);
1588
1589 if (ops != NULL && ops->chat_add_users != NULL)
1590 ops->chat_add_users(conv, cbuddies, new_arrivals);
1591
1592 g_list_free(cbuddies);
1593 }
1594
1595 void
1596 gaim_conv_chat_rename_user(GaimConvChat *chat, const char *old_user,
1597 const char *new_user)
1598 {
1599 GaimConversation *conv;
1600 GaimConversationUiOps *ops;
1601 GaimConnection *gc;
1602 GaimPluginProtocolInfo *prpl_info;
1603 GaimConvChatBuddy *cb;
1604 GaimConvChatBuddyFlags flags;
1605 const char *new_alias = new_user;
1606 char tmp[BUF_LONG];
1607 gboolean is_me = FALSE;
1608
1609 g_return_if_fail(chat != NULL);
1610 g_return_if_fail(old_user != NULL);
1611 g_return_if_fail(new_user != NULL);
1612
1613 conv = gaim_conv_chat_get_conversation(chat);
1614 ops = gaim_conversation_get_ui_ops(conv);
1615
1616 gc = gaim_conversation_get_gc(conv);
1617 g_return_if_fail(gc != NULL);
1618 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
1619 g_return_if_fail(prpl_info != NULL);
1620
1621 flags = gaim_conv_chat_user_get_flags(chat, old_user);
1622 cb = gaim_conv_chat_cb_new(new_user, NULL, flags);
1623 gaim_conv_chat_set_users(chat,
1624 g_list_prepend(gaim_conv_chat_get_users(chat), cb));
1625
1626 if (!strcmp(chat->nick, gaim_normalize(conv->account, old_user))) {
1627 const char *alias;
1628
1629 /* Note this for later. */
1630 is_me = TRUE;
1631
1632 alias = gaim_account_get_alias(conv->account);
1633 if (alias != NULL)
1634 new_alias = alias;
1635 else
1636 {
1637 const char *display_name = gaim_connection_get_display_name(gc);
1638 if (display_name != NULL)
1639 alias = display_name;
1640 }
1641 } else if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
1642 GaimBuddy *buddy;
1643 if ((buddy = gaim_find_buddy(gc->account, new_user)) != NULL)
1644 new_alias = gaim_buddy_get_contact_alias(buddy);
1645 }
1646
1647 if (ops != NULL && ops->chat_rename_user != NULL)
1648 ops->chat_rename_user(conv, old_user, new_user, new_alias);
1649
1650 cb = gaim_conv_chat_cb_find(chat, old_user);
1651
1652 if (cb) {
1653 gaim_conv_chat_set_users(chat,
1654 g_list_remove(gaim_conv_chat_get_users(chat), cb));
1655 gaim_conv_chat_cb_destroy(cb);
1656 }
1657
1658 if (gaim_conv_chat_is_user_ignored(chat, old_user)) {
1659 gaim_conv_chat_unignore(chat, old_user);
1660 gaim_conv_chat_ignore(chat, new_user);
1661 }
1662 else if (gaim_conv_chat_is_user_ignored(chat, new_user))
1663 gaim_conv_chat_unignore(chat, new_user);
1664
1665 if (is_me)
1666 gaim_conv_chat_set_nick(chat, new_user);
1667
1668 if (gaim_prefs_get_bool("/core/conversations/chat/show_nick_change") &&
1669 !gaim_conv_chat_is_user_ignored(chat, new_user)) {
1670
1671 if (is_me) {
1672 char *escaped = g_markup_escape_text(new_user, -1);
1673 g_snprintf(tmp, sizeof(tmp),
1674 _("You are now known as %s"), escaped);
1675 g_free(escaped);
1676 } else {
1677 const char *old_alias = old_user;
1678 const char *new_alias = new_user;
1679 char *escaped;
1680 char *escaped2;
1681
1682 if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
1683 GaimBuddy *buddy;
1684
1685 if ((buddy = gaim_find_buddy(gc->account, old_user)) != NULL)
1686 old_alias = gaim_buddy_get_contact_alias(buddy);
1687 if ((buddy = gaim_find_buddy(gc->account, new_user)) != NULL)
1688 new_alias = gaim_buddy_get_contact_alias(buddy);
1689 }
1690
1691 escaped = g_markup_escape_text(old_alias, -1);
1692 escaped2 = g_markup_escape_text(new_alias, -1);
1693 g_snprintf(tmp, sizeof(tmp),
1694 _("%s is now known as %s"), escaped, escaped2);
1695 g_free(escaped);
1696 g_free(escaped2);
1697 }
1698
1699 gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
1700 }
1701 }
1702
1703 void
1704 gaim_conv_chat_remove_user(GaimConvChat *chat, const char *user, const char *reason)
1705 {
1706 GList *users = g_list_append(NULL, (char *)user);
1707
1708 gaim_conv_chat_remove_users(chat, users, reason);
1709
1710 g_list_free(users);
1711 }
1712
1713 void
1714 gaim_conv_chat_remove_users(GaimConvChat *chat, GList *users, const char *reason)
1715 {
1716 GaimConversation *conv;
1717 GaimConnection *gc;
1718 GaimPluginProtocolInfo *prpl_info;
1719 GaimConversationUiOps *ops;
1720 GaimConvChatBuddy *cb;
1721 GList *l;
1722 gboolean quiet;
1723
1724 g_return_if_fail(chat != NULL);
1725 g_return_if_fail(users != NULL);
1726
1727 conv = gaim_conv_chat_get_conversation(chat);
1728
1729 gc = gaim_conversation_get_gc(conv);
1730 g_return_if_fail(gc != NULL);
1731 prpl_info = GAIM_PLUGIN_PROTOCOL_INFO(gc->prpl);
1732 g_return_if_fail(prpl_info != NULL);
1733
1734 ops = gaim_conversation_get_ui_ops(conv);
1735
1736 for (l = users; l != NULL; l = l->next) {
1737 const char *user = (const char *)l->data;
1738 quiet = GPOINTER_TO_INT(gaim_signal_emit_return_1(gaim_conversations_get_handle(),
1739 "chat-buddy-leaving", conv, user, reason)) |
1740 gaim_conv_chat_is_user_ignored(chat, user);
1741
1742 cb = gaim_conv_chat_cb_find(chat, user);
1743
1744 if (cb) {
1745 gaim_conv_chat_set_users(chat,
1746 g_list_remove(gaim_conv_chat_get_users(chat), cb));
1747 gaim_conv_chat_cb_destroy(cb);
1748 }
1749
1750 /* NOTE: Don't remove them from ignored in case they re-enter. */
1751
1752 if (!quiet) {
1753 const char *alias = user;
1754 char *escaped;
1755 char *tmp;
1756
1757 if (!(prpl_info->options & OPT_PROTO_UNIQUE_CHATNAME)) {
1758 GaimBuddy *buddy;
1759
1760 if ((buddy = gaim_find_buddy(gc->account, user)) != NULL)
1761 alias = gaim_buddy_get_contact_alias(buddy);
1762 }
1763
1764 escaped = g_markup_escape_text(alias, -1);
1765
1766 if (reason == NULL || !*reason)
1767 tmp = g_strdup_printf(_("%s left the room."), escaped);
1768 else {
1769 char *escaped2 = g_markup_escape_text(reason, -1);
1770 tmp = g_strdup_printf(_("%s left the room (%s)."),
1771 escaped, escaped2);
1772 g_free(escaped2);
1773 }
1774 g_free(escaped);
1775
1776 gaim_conversation_write(conv, NULL, tmp, GAIM_MESSAGE_SYSTEM, time(NULL));
1777 g_free(tmp);
1778 }
1779
1780 gaim_signal_emit(gaim_conversations_get_handle(), "chat-buddy-left",
1781 conv, user, reason);
1782 }
1783
1784 if (ops != NULL && ops->chat_remove_users != NULL)
1785 ops->chat_remove_users(conv, users);
1786 }
1787
1788 void
1789 gaim_conv_chat_clear_users(GaimConvChat *chat)
1790 {
1791 GaimConversation *conv;
1792 GaimConversationUiOps *ops;
1793 GList *users, *names = NULL;
1794 GList *l;
1795
1796 g_return_if_fail(chat != NULL);
1797
1798 conv = gaim_conv_chat_get_conversation(chat);
1799 ops = gaim_conversation_get_ui_ops(conv);
1800 users = gaim_conv_chat_get_users(chat);
1801
1802 if (ops != NULL && ops->chat_remove_users != NULL) {
1803 for (l = users; l; l = l->next) {
1804 GaimConvChatBuddy *cb = l->data;
1805 names = g_list_append(names, cb->name);
1806 }
1807 ops->chat_remove_users(conv, names);
1808 g_list_free(names);
1809 }
1810
1811 for (l = users; l; l = l->next)
1812 {
1813 GaimConvChatBuddy *cb = l->data;
1814
1815 gaim_signal_emit(gaim_conversations_get_handle(),
1816 "chat-buddy-leaving", conv, cb->name, NULL);
1817 gaim_signal_emit(gaim_conversations_get_handle(),
1818 "chat-buddy-left", conv, cb->name, NULL);
1819
1820 gaim_conv_chat_cb_destroy(cb);
1821 }
1822
1823 g_list_free(users);
1824 gaim_conv_chat_set_users(chat, NULL);
1825 }
1826
1827
1828 gboolean
1829 gaim_conv_chat_find_user(GaimConvChat *chat, const char *user)
1830 {
1831 g_return_val_if_fail(chat != NULL, FALSE);
1832 g_return_val_if_fail(user != NULL, FALSE);
1833
1834 return (gaim_conv_chat_cb_find(chat, user) != NULL);
1835 }
1836
1837 void
1838 gaim_conv_chat_user_set_flags(GaimConvChat *chat, const char *user,
1839 GaimConvChatBuddyFlags flags)
1840 {
1841 GaimConversation *conv;
1842 GaimConversationUiOps *ops;
1843 GaimConvChatBuddy *cb;
1844 GaimConvChatBuddyFlags oldflags;
1845
1846 g_return_if_fail(chat != NULL);
1847 g_return_if_fail(user != NULL);
1848
1849 cb = gaim_conv_chat_cb_find(chat, user);
1850
1851 if (!cb)
1852 return;
1853
1854 if (flags == cb->flags)
1855 return;
1856
1857 oldflags = cb->flags;
1858 cb->flags = flags;
1859
1860 conv = gaim_conv_chat_get_conversation(chat);
1861 ops = gaim_conversation_get_ui_ops(conv);
1862
1863 if (ops != NULL && ops->chat_update_user != NULL)
1864 ops->chat_update_user(conv, user);
1865
1866 gaim_signal_emit(gaim_conversations_get_handle(),
1867 "chat-buddy-flags", conv, user, oldflags, flags);
1868 }
1869
1870 GaimConvChatBuddyFlags
1871 gaim_conv_chat_user_get_flags(GaimConvChat *chat, const char *user)
1872 {
1873 GaimConvChatBuddy *cb;
1874
1875 g_return_val_if_fail(chat != NULL, 0);
1876 g_return_val_if_fail(user != NULL, 0);
1877
1878 cb = gaim_conv_chat_cb_find(chat, user);
1879
1880 if (!cb)
1881 return GAIM_CBFLAGS_NONE;
1882
1883 return cb->flags;
1884 }
1885
1886 void gaim_conv_chat_set_nick(GaimConvChat *chat, const char *nick) {
1887 g_return_if_fail(chat != NULL);
1888
1889 g_free(chat->nick);
1890 chat->nick = g_strdup(gaim_normalize(chat->conv->account, nick));
1891 }
1892
1893 const char *gaim_conv_chat_get_nick(GaimConvChat *chat) {
1894 g_return_val_if_fail(chat != NULL, NULL);
1895
1896 return chat->nick;
1897 }
1898
1899 GaimConversation *
1900 gaim_find_chat(const GaimConnection *gc, int id)
1901 {
1902 GList *l;
1903 GaimConversation *conv;
1904
1905 for (l = gaim_get_chats(); l != NULL; l = l->next) {
1906 conv = (GaimConversation *)l->data;
1907
1908 if (gaim_conv_chat_get_id(GAIM_CONV_CHAT(conv)) == id &&
1909 gaim_conversation_get_gc(conv) == gc)
1910 return conv;
1911 }
1912
1913 return NULL;
1914 }
1915
1916 void
1917 gaim_conv_chat_left(GaimConvChat *chat)
1918 {
1919 g_return_if_fail(chat != NULL);
1920
1921 chat->left = TRUE;
1922 gaim_conversation_update(chat->conv, GAIM_CONV_UPDATE_CHATLEFT);
1923 }
1924
1925 gboolean
1926 gaim_conv_chat_has_left(GaimConvChat *chat)
1927 {
1928 g_return_val_if_fail(chat != NULL, TRUE);
1929
1930 return chat->left;
1931 }
1932 GaimConvChatBuddy *
1933 gaim_conv_chat_cb_new(const char *name, const char *alias, GaimConvChatBuddyFlags flags)
1934 {
1935 GaimConvChatBuddy *cb;
1936
1937 g_return_val_if_fail(name != NULL, NULL);
1938
1939 cb = g_new0(GaimConvChatBuddy, 1);
1940 cb->name = g_strdup(name);
1941 cb->flags = flags;
1942 cb->alias = g_strdup(alias);
1943
1944 GAIM_DBUS_REGISTER_POINTER(cb, GaimConvChatBuddy);
1945 return cb;
1946 }
1947
1948 GaimConvChatBuddy *
1949 gaim_conv_chat_cb_find(GaimConvChat *chat, const char *name)
1950 {
1951 GList *l;
1952 GaimConvChatBuddy *cb = NULL;
1953
1954 g_return_val_if_fail(chat != NULL, NULL);
1955 g_return_val_if_fail(name != NULL, NULL);
1956
1957 for (l = gaim_conv_chat_get_users(chat); l; l = l->next) {
1958 cb = l->data;
1959 if (!gaim_utf8_strcasecmp(cb->name, name))
1960 return cb;
1961 }
1962
1963 return NULL;
1964 }
1965
1966 void
1967 gaim_conv_chat_cb_destroy(GaimConvChatBuddy *cb)
1968 {
1969 if (cb == NULL)
1970 return;
1971
1972 g_free(cb->alias);
1973 g_free(cb->alias_key);
1974 g_free(cb->name);
1975
1976 GAIM_DBUS_UNREGISTER_POINTER(cb);
1977 g_free(cb);
1978 }
1979
1980 const char *
1981 gaim_conv_chat_cb_get_name(GaimConvChatBuddy *cb)
1982 {
1983 g_return_val_if_fail(cb != NULL, NULL);
1984
1985 return cb->name;
1986 }
1987
1988 void *
1989 gaim_conversations_get_handle(void)
1990 {
1991 static int handle;
1992
1993 return &handle;
1994 }
1995
1996 void
1997 gaim_conversations_init(void)
1998 {
1999 void *handle = gaim_conversations_get_handle();
2000
2001 /**********************************************************************
2002 * Register preferences
2003 **********************************************************************/
2004
2005 /* Conversations */
2006 gaim_prefs_add_none("/core/conversations");
2007
2008 /* Conversations -> Chat */
2009 gaim_prefs_add_none("/core/conversations/chat");
2010 gaim_prefs_add_bool("/core/conversations/chat/show_nick_change", TRUE);
2011
2012 /* Conversations -> IM */
2013 gaim_prefs_add_none("/core/conversations/im");
2014 gaim_prefs_add_bool("/core/conversations/im/send_typing", TRUE);
2015
2016
2017 /**********************************************************************
2018 * Register signals
2019 **********************************************************************/
2020 gaim_signal_register(handle, "writing-im-msg",
2021 gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
2022 gaim_value_new(GAIM_TYPE_BOOLEAN), 5,
2023 gaim_value_new(GAIM_TYPE_SUBTYPE,
2024 GAIM_SUBTYPE_ACCOUNT),
2025 gaim_value_new(GAIM_TYPE_STRING),
2026 gaim_value_new_outgoing(GAIM_TYPE_STRING),
2027 gaim_value_new(GAIM_TYPE_SUBTYPE,
2028 GAIM_SUBTYPE_CONVERSATION),
2029 gaim_value_new(GAIM_TYPE_UINT));
2030
2031 gaim_signal_register(handle, "wrote-im-msg",
2032 gaim_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
2033 NULL, 5,
2034 gaim_value_new(GAIM_TYPE_SUBTYPE,
2035 GAIM_SUBTYPE_ACCOUNT),
2036 gaim_value_new(GAIM_TYPE_STRING),
2037 gaim_value_new(GAIM_TYPE_STRING),
2038 gaim_value_new(GAIM_TYPE_SUBTYPE,
2039 GAIM_SUBTYPE_CONVERSATION),
2040 gaim_value_new(GAIM_TYPE_UINT));
2041
2042 gaim_signal_register(handle, "sending-im-msg",
2043 gaim_marshal_VOID__POINTER_POINTER_POINTER,
2044 NULL, 3,
2045 gaim_value_new(GAIM_TYPE_SUBTYPE,
2046 GAIM_SUBTYPE_ACCOUNT),
2047 gaim_value_new(GAIM_TYPE_STRING),
2048 gaim_value_new_outgoing(GAIM_TYPE_STRING));
2049
2050 gaim_signal_register(handle, "sent-im-msg",
2051 gaim_marshal_VOID__POINTER_POINTER_POINTER,
2052 NULL, 3,
2053 gaim_value_new(GAIM_TYPE_SUBTYPE,
2054 GAIM_SUBTYPE_ACCOUNT),
2055 gaim_value_new(GAIM_TYPE_STRING),
2056 gaim_value_new(GAIM_TYPE_STRING));
2057
2058 gaim_signal_register(handle, "receiving-im-msg",
2059 gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
2060 gaim_value_new(GAIM_TYPE_BOOLEAN), 5,
2061 gaim_value_new(GAIM_TYPE_SUBTYPE,
2062 GAIM_SUBTYPE_ACCOUNT),
2063 gaim_value_new_outgoing(GAIM_TYPE_STRING),
2064 gaim_value_new_outgoing(GAIM_TYPE_STRING),
2065 gaim_value_new(GAIM_TYPE_SUBTYPE,
2066 GAIM_SUBTYPE_CONVERSATION),
2067 gaim_value_new_outgoing(GAIM_TYPE_UINT));
2068
2069 gaim_signal_register(handle, "received-im-msg",
2070 gaim_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
2071 NULL, 5,
2072 gaim_value_new(GAIM_TYPE_SUBTYPE,
2073 GAIM_SUBTYPE_ACCOUNT),
2074 gaim_value_new(GAIM_TYPE_STRING),
2075 gaim_value_new(GAIM_TYPE_STRING),
2076 gaim_value_new(GAIM_TYPE_SUBTYPE,
2077 GAIM_SUBTYPE_CONVERSATION),
2078 gaim_value_new(GAIM_TYPE_UINT));
2079
2080 gaim_signal_register(handle, "writing-chat-msg",
2081 gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
2082 gaim_value_new(GAIM_TYPE_BOOLEAN), 5,
2083 gaim_value_new(GAIM_TYPE_SUBTYPE,
2084 GAIM_SUBTYPE_ACCOUNT),
2085 gaim_value_new(GAIM_TYPE_STRING),
2086 gaim_value_new_outgoing(GAIM_TYPE_STRING),
2087 gaim_value_new(GAIM_TYPE_SUBTYPE,
2088 GAIM_SUBTYPE_CONVERSATION),
2089 gaim_value_new(GAIM_TYPE_UINT));
2090
2091 gaim_signal_register(handle, "wrote-chat-msg",
2092 gaim_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
2093 NULL, 5,
2094 gaim_value_new(GAIM_TYPE_SUBTYPE,
2095 GAIM_SUBTYPE_ACCOUNT),
2096 gaim_value_new(GAIM_TYPE_STRING),
2097 gaim_value_new(GAIM_TYPE_STRING),
2098 gaim_value_new(GAIM_TYPE_SUBTYPE,
2099 GAIM_SUBTYPE_CONVERSATION),
2100 gaim_value_new(GAIM_TYPE_UINT));
2101
2102 gaim_signal_register(handle, "sending-chat-msg",
2103 gaim_marshal_VOID__POINTER_POINTER_UINT, NULL, 3,
2104 gaim_value_new(GAIM_TYPE_SUBTYPE,
2105 GAIM_SUBTYPE_ACCOUNT),
2106 gaim_value_new_outgoing(GAIM_TYPE_STRING),
2107 gaim_value_new(GAIM_TYPE_UINT));
2108
2109 gaim_signal_register(handle, "sent-chat-msg",
2110 gaim_marshal_VOID__POINTER_POINTER_UINT, NULL, 3,
2111 gaim_value_new(GAIM_TYPE_SUBTYPE,
2112 GAIM_SUBTYPE_ACCOUNT),
2113 gaim_value_new(GAIM_TYPE_STRING),
2114 gaim_value_new(GAIM_TYPE_UINT));
2115
2116 gaim_signal_register(handle, "receiving-chat-msg",
2117 gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
2118 gaim_value_new(GAIM_TYPE_BOOLEAN), 5,
2119 gaim_value_new(GAIM_TYPE_SUBTYPE,
2120 GAIM_SUBTYPE_ACCOUNT),
2121 gaim_value_new_outgoing(GAIM_TYPE_STRING),
2122 gaim_value_new_outgoing(GAIM_TYPE_STRING),
2123 gaim_value_new(GAIM_TYPE_SUBTYPE,
2124 GAIM_SUBTYPE_CONVERSATION),
2125 gaim_value_new_outgoing(GAIM_TYPE_UINT));
2126
2127 gaim_signal_register(handle, "received-chat-msg",
2128 gaim_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT,
2129 NULL, 5,
2130 gaim_value_new(GAIM_TYPE_SUBTYPE,
2131 GAIM_SUBTYPE_ACCOUNT),
2132 gaim_value_new(GAIM_TYPE_STRING),
2133 gaim_value_new(GAIM_TYPE_STRING),
2134 gaim_value_new(GAIM_TYPE_SUBTYPE,
2135 GAIM_SUBTYPE_CONVERSATION),
2136 gaim_value_new(GAIM_TYPE_UINT));
2137
2138 gaim_signal_register(handle, "conversation-created",
2139 gaim_marshal_VOID__POINTER, NULL, 1,
2140 gaim_value_new(GAIM_TYPE_SUBTYPE,
2141 GAIM_SUBTYPE_CONVERSATION));
2142
2143 gaim_signal_register(handle, "conversation-updated",
2144 gaim_marshal_VOID__POINTER_UINT, NULL, 2,
2145 gaim_value_new(GAIM_TYPE_SUBTYPE,
2146 GAIM_SUBTYPE_CONVERSATION),
2147 gaim_value_new(GAIM_TYPE_UINT));
2148
2149 gaim_signal_register(handle, "deleting-conversation",
2150 gaim_marshal_VOID__POINTER, NULL, 1,
2151 gaim_value_new(GAIM_TYPE_SUBTYPE,
2152 GAIM_SUBTYPE_CONVERSATION));
2153
2154 gaim_signal_register(handle, "buddy-typing",
2155 gaim_marshal_VOID__POINTER_POINTER, NULL, 2,
2156 gaim_value_new(GAIM_TYPE_SUBTYPE,
2157 GAIM_SUBTYPE_ACCOUNT),
2158 gaim_value_new(GAIM_TYPE_STRING));
2159
2160 gaim_signal_register(handle, "buddy-typed",
2161 gaim_marshal_VOID__POINTER_POINTER, NULL, 2,
2162 gaim_value_new(GAIM_TYPE_SUBTYPE,
2163 GAIM_SUBTYPE_ACCOUNT),
2164 gaim_value_new(GAIM_TYPE_STRING));
2165
2166 gaim_signal_register(handle, "buddy-typing-stopped",
2167 gaim_marshal_VOID__POINTER_POINTER, NULL, 2,
2168 gaim_value_new(GAIM_TYPE_SUBTYPE,
2169 GAIM_SUBTYPE_ACCOUNT),
2170 gaim_value_new(GAIM_TYPE_STRING));
2171
2172 gaim_signal_register(handle, "chat-buddy-joining",
2173 gaim_marshal_BOOLEAN__POINTER_POINTER_UINT,
2174 gaim_value_new(GAIM_TYPE_BOOLEAN), 3,
2175 gaim_value_new(GAIM_TYPE_SUBTYPE,
2176 GAIM_SUBTYPE_CONVERSATION),
2177 gaim_value_new(GAIM_TYPE_STRING),
2178 gaim_value_new(GAIM_TYPE_UINT));
2179
2180 gaim_signal_register(handle, "chat-buddy-joined",
2181 gaim_marshal_VOID__POINTER_POINTER_UINT_UINT, NULL, 4,
2182 gaim_value_new(GAIM_TYPE_SUBTYPE,
2183 GAIM_SUBTYPE_CONVERSATION),
2184 gaim_value_new(GAIM_TYPE_STRING),
2185 gaim_value_new(GAIM_TYPE_UINT),
2186 gaim_value_new(GAIM_TYPE_BOOLEAN));
2187
2188 gaim_signal_register(handle, "chat-buddy-flags",
2189 gaim_marshal_VOID__POINTER_POINTER_UINT_UINT, NULL, 4,
2190 gaim_value_new(GAIM_TYPE_SUBTYPE,
2191 GAIM_SUBTYPE_CONVERSATION),
2192 gaim_value_new(GAIM_TYPE_STRING),
2193 gaim_value_new(GAIM_TYPE_UINT),
2194 gaim_value_new(GAIM_TYPE_UINT));
2195
2196 gaim_signal_register(handle, "chat-buddy-leaving",
2197 gaim_marshal_BOOLEAN__POINTER_POINTER_POINTER,
2198 gaim_value_new(GAIM_TYPE_BOOLEAN), 3,
2199 gaim_value_new(GAIM_TYPE_SUBTYPE,
2200 GAIM_SUBTYPE_CONVERSATION),
2201 gaim_value_new(GAIM_TYPE_STRING),
2202 gaim_value_new(GAIM_TYPE_STRING));
2203
2204 gaim_signal_register(handle, "chat-buddy-left",
2205 gaim_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
2206 gaim_value_new(GAIM_TYPE_SUBTYPE,
2207 GAIM_SUBTYPE_CONVERSATION),
2208 gaim_value_new(GAIM_TYPE_STRING),
2209 gaim_value_new(GAIM_TYPE_STRING));
2210
2211 gaim_signal_register(handle, "chat-inviting-user",
2212 gaim_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
2213 gaim_value_new(GAIM_TYPE_SUBTYPE,
2214 GAIM_SUBTYPE_CONVERSATION),
2215 gaim_value_new(GAIM_TYPE_STRING),
2216 gaim_value_new_outgoing(GAIM_TYPE_STRING));
2217
2218 gaim_signal_register(handle, "chat-invited-user",
2219 gaim_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
2220 gaim_value_new(GAIM_TYPE_SUBTYPE,
2221 GAIM_SUBTYPE_CONVERSATION),
2222 gaim_value_new(GAIM_TYPE_STRING),
2223 gaim_value_new(GAIM_TYPE_STRING));
2224
2225 gaim_signal_register(handle, "chat-invited",
2226 gaim_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER,
2227 NULL, 5,
2228 gaim_value_new(GAIM_TYPE_SUBTYPE,
2229 GAIM_SUBTYPE_ACCOUNT),
2230 gaim_value_new(GAIM_TYPE_STRING),
2231 gaim_value_new(GAIM_TYPE_STRING),
2232 gaim_value_new(GAIM_TYPE_STRING),
2233 gaim_value_new(GAIM_TYPE_POINTER));
2234
2235 gaim_signal_register(handle, "chat-joined",
2236 gaim_marshal_VOID__POINTER, NULL, 1,
2237 gaim_value_new(GAIM_TYPE_SUBTYPE,
2238 GAIM_SUBTYPE_CONVERSATION));
2239
2240 gaim_signal_register(handle, "chat-left",
2241 gaim_marshal_VOID__POINTER, NULL, 1,
2242 gaim_value_new(GAIM_TYPE_SUBTYPE,
2243 GAIM_SUBTYPE_CONVERSATION));
2244
2245 gaim_signal_register(handle, "chat-topic-changed",
2246 gaim_marshal_VOID__POINTER_POINTER_POINTER, NULL, 3,
2247 gaim_value_new(GAIM_TYPE_SUBTYPE,
2248 GAIM_SUBTYPE_CONVERSATION),
2249 gaim_value_new(GAIM_TYPE_STRING),
2250 gaim_value_new(GAIM_TYPE_STRING));
2251 }
2252
2253 void
2254 gaim_conversations_uninit(void)
2255 {
2256 while (conversations)
2257 gaim_conversation_destroy((GaimConversation*)conversations->data);
2258 gaim_signals_unregister_by_instance(gaim_conversations_get_handle());
2259 }