4 * Purple 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
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 #include "conversation.h"
26 #include "dbus-maybe.h"
36 #define SEND_TYPED_TIMEOUT_SECONDS 5
38 static GList
*conversations
= NULL
;
39 static GList
*ims
= NULL
;
40 static GList
*chats
= NULL
;
41 static PurpleConversationUiOps
*default_ops
= NULL
;
44 * A hash table used for efficient lookups of conversations by name.
45 * struct _purple_hconv => PurpleConversation*
47 static GHashTable
*conversation_cache
= NULL
;
49 struct _purple_hconv
{
50 PurpleConversationType type
;
52 const PurpleAccount
*account
;
55 static guint
_purple_conversations_hconv_hash(struct _purple_hconv
*hc
)
57 return g_str_hash(hc
->name
) ^ hc
->type
^ g_direct_hash(hc
->account
);
60 static guint
_purple_conversations_hconv_equal(struct _purple_hconv
*hc1
, struct _purple_hconv
*hc2
)
62 return (hc1
->type
== hc2
->type
&&
63 hc1
->account
== hc2
->account
&&
64 g_str_equal(hc1
->name
, hc2
->name
));
67 static void _purple_conversations_hconv_free_key(struct _purple_hconv
*hc
)
74 purple_conversations_set_ui_ops(PurpleConversationUiOps
*ops
)
80 reset_typing_cb(gpointer data
)
82 PurpleConversation
*c
= (PurpleConversation
*)data
;
85 im
= PURPLE_CONV_IM(c
);
87 purple_conv_im_set_typing_state(im
, PURPLE_NOT_TYPING
);
88 purple_conv_im_stop_typing_timeout(im
);
94 send_typed_cb(gpointer data
)
96 PurpleConversation
*conv
= (PurpleConversation
*)data
;
100 g_return_val_if_fail(conv
!= NULL
, FALSE
);
102 gc
= purple_conversation_get_gc(conv
);
103 name
= purple_conversation_get_name(conv
);
105 if (gc
!= NULL
&& name
!= NULL
) {
106 /* We set this to 1 so that PURPLE_TYPING will be sent
107 * if the Purple user types anything else.
109 purple_conv_im_set_type_again(PURPLE_CONV_IM(conv
), 1);
111 serv_send_typing(gc
, name
, PURPLE_TYPED
);
113 purple_debug(PURPLE_DEBUG_MISC
, "conversation", "typed...\n");
120 common_send(PurpleConversation
*conv
, const char *message
, PurpleMessageFlags msgflags
)
122 PurpleConversationType type
;
123 PurpleAccount
*account
;
124 PurpleConnection
*gc
;
125 char *displayed
= NULL
, *sent
= NULL
;
128 if (*message
== '\0')
131 account
= purple_conversation_get_account(conv
);
132 gc
= purple_conversation_get_gc(conv
);
134 g_return_if_fail(account
!= NULL
);
135 g_return_if_fail(gc
!= NULL
);
137 type
= purple_conversation_get_type(conv
);
139 /* Always linkfy the text for display, unless we're
140 * explicitly asked to do otheriwse*/
141 if (!(msgflags
& PURPLE_MESSAGE_INVISIBLE
)) {
142 if(msgflags
& PURPLE_MESSAGE_NO_LINKIFY
)
143 displayed
= g_strdup(message
);
145 displayed
= purple_markup_linkify(message
);
148 if (displayed
&& (conv
->features
& PURPLE_CONNECTION_HTML
) &&
149 !(msgflags
& PURPLE_MESSAGE_RAW
)) {
150 sent
= g_strdup(displayed
);
152 sent
= g_strdup(message
);
154 msgflags
|= PURPLE_MESSAGE_SEND
;
156 if (type
== PURPLE_CONV_TYPE_IM
) {
157 PurpleConvIm
*im
= PURPLE_CONV_IM(conv
);
159 purple_signal_emit(purple_conversations_get_handle(), "sending-im-msg",
161 purple_conversation_get_name(conv
), &sent
);
163 if (sent
!= NULL
&& sent
[0] != '\0') {
165 err
= serv_send_im(gc
, purple_conversation_get_name(conv
),
168 if ((err
> 0) && (displayed
!= NULL
))
169 purple_conv_im_write(im
, NULL
, displayed
, msgflags
, time(NULL
));
171 purple_signal_emit(purple_conversations_get_handle(), "sent-im-msg",
173 purple_conversation_get_name(conv
), sent
);
177 purple_signal_emit(purple_conversations_get_handle(), "sending-chat-msg",
179 purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv
)));
181 if (sent
!= NULL
&& sent
[0] != '\0') {
182 err
= serv_chat_send(gc
, purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv
)), sent
, msgflags
);
184 purple_signal_emit(purple_conversations_get_handle(), "sent-chat-msg",
186 purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv
)));
194 who
= purple_conversation_get_name(conv
);
197 msg
= _("Unable to send message: The message is too large.");
199 if (!purple_conv_present_error(who
, account
, msg
)) {
200 char *msg2
= g_strdup_printf(_("Unable to send message to %s."), who
);
201 purple_notify_error(gc
, NULL
, msg2
, _("The message is too large."));
205 else if (err
== -ENOTCONN
) {
206 purple_debug(PURPLE_DEBUG_ERROR
, "conversation",
207 "Not yet connected.\n");
210 msg
= _("Unable to send message.");
212 if (!purple_conv_present_error(who
, account
, msg
)) {
213 char *msg2
= g_strdup_printf(_("Unable to send message to %s."), who
);
214 purple_notify_error(gc
, NULL
, msg2
, NULL
);
225 open_log(PurpleConversation
*conv
)
227 conv
->logs
= g_list_append(NULL
, purple_log_new(conv
->type
== PURPLE_CONV_TYPE_CHAT
? PURPLE_LOG_CHAT
:
228 PURPLE_LOG_IM
, conv
->name
, conv
->account
,
229 conv
, time(NULL
), NULL
));
232 /* Functions that deal with PurpleConvMessage */
235 add_message_to_history(PurpleConversation
*conv
, const char *who
, const char *alias
,
236 const char *message
, PurpleMessageFlags flags
, time_t when
)
238 PurpleConvMessage
*msg
;
239 PurpleConnection
*gc
;
241 gc
= purple_account_get_connection(conv
->account
);
243 if (flags
& PURPLE_MESSAGE_SEND
) {
244 const char *me
= NULL
;
246 me
= purple_connection_get_display_name(gc
);
248 me
= conv
->account
->username
;
252 msg
= g_new0(PurpleConvMessage
, 1);
253 PURPLE_DBUS_REGISTER_POINTER(msg
, PurpleConvMessage
);
254 msg
->who
= g_strdup(who
);
255 msg
->alias
= g_strdup(alias
);
257 msg
->what
= g_strdup(message
);
261 conv
->message_history
= g_list_prepend(conv
->message_history
, msg
);
265 free_conv_message(PurpleConvMessage
*msg
)
270 PURPLE_DBUS_UNREGISTER_POINTER(msg
);
275 message_history_free(GList
*list
)
277 g_list_foreach(list
, (GFunc
)free_conv_message
, NULL
);
281 /**************************************************************************
283 **************************************************************************/
285 purple_conversation_chat_cleanup_for_rejoin(PurpleConversation
*conv
)
288 PurpleAccount
*account
;
289 PurpleConnection
*gc
;
291 account
= purple_conversation_get_account(conv
);
293 purple_conversation_close_logs(conv
);
296 gc
= purple_account_get_connection(account
);
298 if ((disp
= purple_connection_get_display_name(gc
)) != NULL
)
299 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(conv
), disp
);
302 purple_conv_chat_set_nick(PURPLE_CONV_CHAT(conv
),
303 purple_account_get_username(account
));
306 purple_conv_chat_clear_users(PURPLE_CONV_CHAT(conv
));
307 purple_conv_chat_set_topic(PURPLE_CONV_CHAT(conv
), NULL
, NULL
);
308 PURPLE_CONV_CHAT(conv
)->left
= FALSE
;
310 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_CHATLEFT
);
314 purple_conversation_new(PurpleConversationType type
, PurpleAccount
*account
,
317 PurpleConversation
*conv
;
318 PurpleConnection
*gc
;
319 PurpleConversationUiOps
*ops
;
320 struct _purple_hconv
*hc
;
322 g_return_val_if_fail(type
!= PURPLE_CONV_TYPE_UNKNOWN
, NULL
);
323 g_return_val_if_fail(account
!= NULL
, NULL
);
324 g_return_val_if_fail(name
!= NULL
, NULL
);
326 /* Check if this conversation already exists. */
327 if ((conv
= purple_find_conversation_with_account(type
, name
, account
)) != NULL
)
329 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
&&
330 !purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv
))) {
331 purple_debug_warning("conversation", "Trying to create multiple "
332 "chats (%s) with the same name is deprecated and will be "
333 "removed in libpurple 3.0.0", name
);
337 * This hack is necessary because some prpls (MSN) have unnamed chats
338 * that all use the same name. A PurpleConversation for one of those
339 * is only ever re-used if the user has left, so calls to
340 * purple_conversation_new need to fall-through to creating a new
342 * TODO 3.0.0: Remove this workaround and mandate unique names.
344 if (purple_conversation_get_type(conv
) != PURPLE_CONV_TYPE_CHAT
||
345 purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv
)))
347 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
)
348 purple_conversation_chat_cleanup_for_rejoin(conv
);
354 gc
= purple_account_get_connection(account
);
355 g_return_val_if_fail(gc
!= NULL
, NULL
);
357 conv
= g_new0(PurpleConversation
, 1);
358 PURPLE_DBUS_REGISTER_POINTER(conv
, PurpleConversation
);
361 conv
->account
= account
;
362 conv
->name
= g_strdup(name
);
363 conv
->title
= g_strdup(name
);
364 conv
->data
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
366 /* copy features from the connection. */
367 conv
->features
= gc
->flags
;
369 if (type
== PURPLE_CONV_TYPE_IM
)
371 PurpleBuddyIcon
*icon
;
372 conv
->u
.im
= g_new0(PurpleConvIm
, 1);
373 conv
->u
.im
->conv
= conv
;
374 PURPLE_DBUS_REGISTER_POINTER(conv
->u
.im
, PurpleConvIm
);
376 ims
= g_list_prepend(ims
, conv
);
377 if ((icon
= purple_buddy_icons_find(account
, name
)))
379 purple_conv_im_set_icon(conv
->u
.im
, icon
);
380 /* purple_conv_im_set_icon refs the icon. */
381 purple_buddy_icon_unref(icon
);
384 if (purple_prefs_get_bool("/purple/logging/log_ims"))
386 purple_conversation_set_logging(conv
, TRUE
);
390 else if (type
== PURPLE_CONV_TYPE_CHAT
)
394 conv
->u
.chat
= g_new0(PurpleConvChat
, 1);
395 conv
->u
.chat
->conv
= conv
;
396 PURPLE_DBUS_REGISTER_POINTER(conv
->u
.chat
, PurpleConvChat
);
398 chats
= g_list_prepend(chats
, conv
);
400 if ((disp
= purple_connection_get_display_name(account
->gc
)))
401 purple_conv_chat_set_nick(conv
->u
.chat
, disp
);
403 purple_conv_chat_set_nick(conv
->u
.chat
,
404 purple_account_get_username(account
));
406 if (purple_prefs_get_bool("/purple/logging/log_chats"))
408 purple_conversation_set_logging(conv
, TRUE
);
413 conversations
= g_list_prepend(conversations
, conv
);
415 hc
= g_new(struct _purple_hconv
, 1);
416 hc
->name
= g_strdup(purple_normalize(account
, conv
->name
));
417 hc
->account
= account
;
420 g_hash_table_insert(conversation_cache
, hc
, conv
);
422 /* Auto-set the title. */
423 purple_conversation_autoset_title(conv
);
425 /* Don't move this.. it needs to be one of the last things done otherwise
426 * it causes mysterious crashes on my system.
429 ops
= conv
->ui_ops
= default_ops
;
430 if (ops
!= NULL
&& ops
->create_conversation
!= NULL
)
431 ops
->create_conversation(conv
);
433 purple_signal_emit(purple_conversations_get_handle(),
434 "conversation-created", conv
);
440 purple_conversation_destroy(PurpleConversation
*conv
)
442 PurplePluginProtocolInfo
*prpl_info
= NULL
;
443 PurpleConversationUiOps
*ops
;
444 PurpleConnection
*gc
;
446 struct _purple_hconv hc
;
448 g_return_if_fail(conv
!= NULL
);
450 purple_request_close_with_handle(conv
);
452 ops
= purple_conversation_get_ui_ops(conv
);
453 gc
= purple_conversation_get_gc(conv
);
454 name
= purple_conversation_get_name(conv
);
458 /* Still connected */
459 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
461 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
)
463 if (purple_prefs_get_bool("/purple/conversations/im/send_typing"))
464 serv_send_typing(gc
, name
, PURPLE_NOT_TYPING
);
466 if (gc
&& prpl_info
->convo_closed
!= NULL
)
467 prpl_info
->convo_closed(gc
, name
);
469 else if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
)
471 int chat_id
= purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv
));
474 * This is unfortunately necessary, because calling
475 * serv_chat_leave() calls this purple_conversation_destroy(),
476 * which leads to two calls here.. We can't just return after
477 * this, because then it'll return on the next pass. So, since
478 * serv_got_chat_left(), which is eventually called from the
479 * prpl that serv_chat_leave() calls, removes this conversation
480 * from the gc's buddy_chats list, we're going to check to see
481 * if this exists in the list. If so, we want to return after
482 * calling this, because it'll be called again. If not, fall
483 * through, because it'll have already been removed, and we'd
484 * be on the 2nd pass.
486 * Long paragraph. <-- Short sentence.
491 if (gc
&& g_slist_find(gc
->buddy_chats
, conv
) != NULL
) {
492 serv_chat_leave(gc
, chat_id
);
498 * Instead of all of that, lets just close the window when
499 * the user tells us to, and let the prpl deal with the
500 * internals on it's own time. Don't do this if the prpl already
501 * knows it left the chat.
503 if (!purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv
)))
504 serv_chat_leave(gc
, chat_id
);
507 * If they didn't call serv_got_chat_left by now, it's too late.
508 * So we better do it for them before we destroy the thing.
510 if (!purple_conv_chat_has_left(PURPLE_CONV_CHAT(conv
)))
511 serv_got_chat_left(gc
, chat_id
);
515 /* remove from conversations and im/chats lists prior to emit */
516 conversations
= g_list_remove(conversations
, conv
);
518 if(conv
->type
==PURPLE_CONV_TYPE_IM
)
519 ims
= g_list_remove(ims
, conv
);
520 else if(conv
->type
==PURPLE_CONV_TYPE_CHAT
)
521 chats
= g_list_remove(chats
, conv
);
523 hc
.name
= (gchar
*)purple_normalize(conv
->account
, conv
->name
);
524 hc
.account
= conv
->account
;
525 hc
.type
= conv
->type
;
527 g_hash_table_remove(conversation_cache
, &hc
);
529 purple_signal_emit(purple_conversations_get_handle(),
530 "deleting-conversation", conv
);
538 if (conv
->type
== PURPLE_CONV_TYPE_IM
) {
539 purple_conv_im_stop_typing_timeout(conv
->u
.im
);
540 purple_conv_im_stop_send_typed_timeout(conv
->u
.im
);
542 purple_buddy_icon_unref(conv
->u
.im
->icon
);
543 conv
->u
.im
->icon
= NULL
;
545 PURPLE_DBUS_UNREGISTER_POINTER(conv
->u
.im
);
549 else if (conv
->type
== PURPLE_CONV_TYPE_CHAT
) {
551 g_list_foreach(conv
->u
.chat
->in_room
, (GFunc
)purple_conv_chat_cb_destroy
, NULL
);
552 g_list_free(conv
->u
.chat
->in_room
);
554 g_list_foreach(conv
->u
.chat
->ignored
, (GFunc
)g_free
, NULL
);
555 g_list_free(conv
->u
.chat
->ignored
);
557 conv
->u
.chat
->in_room
= NULL
;
558 conv
->u
.chat
->ignored
= NULL
;
560 g_free(conv
->u
.chat
->who
);
561 conv
->u
.chat
->who
= NULL
;
563 g_free(conv
->u
.chat
->topic
);
564 conv
->u
.chat
->topic
= NULL
;
566 g_free(conv
->u
.chat
->nick
);
568 PURPLE_DBUS_UNREGISTER_POINTER(conv
->u
.chat
);
569 g_free(conv
->u
.chat
);
573 g_hash_table_destroy(conv
->data
);
576 if (ops
!= NULL
&& ops
->destroy_conversation
!= NULL
)
577 ops
->destroy_conversation(conv
);
579 purple_conversation_close_logs(conv
);
581 purple_conversation_clear_message_history(conv
);
583 PURPLE_DBUS_UNREGISTER_POINTER(conv
);
590 purple_conversation_present(PurpleConversation
*conv
) {
591 PurpleConversationUiOps
*ops
;
593 g_return_if_fail(conv
!= NULL
);
595 ops
= purple_conversation_get_ui_ops(conv
);
596 if(ops
&& ops
->present
)
602 purple_conversation_set_features(PurpleConversation
*conv
, PurpleConnectionFlags features
)
604 g_return_if_fail(conv
!= NULL
);
606 conv
->features
= features
;
608 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_FEATURES
);
612 PurpleConnectionFlags
613 purple_conversation_get_features(PurpleConversation
*conv
)
615 g_return_val_if_fail(conv
!= NULL
, 0);
616 return conv
->features
;
620 PurpleConversationType
621 purple_conversation_get_type(const PurpleConversation
*conv
)
623 g_return_val_if_fail(conv
!= NULL
, PURPLE_CONV_TYPE_UNKNOWN
);
629 purple_conversation_set_ui_ops(PurpleConversation
*conv
,
630 PurpleConversationUiOps
*ops
)
632 g_return_if_fail(conv
!= NULL
);
634 if (conv
->ui_ops
== ops
)
637 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->destroy_conversation
!= NULL
)
638 conv
->ui_ops
->destroy_conversation(conv
);
640 conv
->ui_data
= NULL
;
645 PurpleConversationUiOps
*
646 purple_conversation_get_ui_ops(const PurpleConversation
*conv
)
648 g_return_val_if_fail(conv
!= NULL
, NULL
);
654 purple_conversation_set_account(PurpleConversation
*conv
, PurpleAccount
*account
)
656 g_return_if_fail(conv
!= NULL
);
658 if (account
== purple_conversation_get_account(conv
))
661 conv
->account
= account
;
663 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_ACCOUNT
);
667 purple_conversation_get_account(const PurpleConversation
*conv
)
669 g_return_val_if_fail(conv
!= NULL
, NULL
);
671 return conv
->account
;
675 purple_conversation_get_gc(const PurpleConversation
*conv
)
677 PurpleAccount
*account
;
679 g_return_val_if_fail(conv
!= NULL
, NULL
);
681 account
= purple_conversation_get_account(conv
);
690 purple_conversation_set_title(PurpleConversation
*conv
, const char *title
)
692 g_return_if_fail(conv
!= NULL
);
693 g_return_if_fail(title
!= NULL
);
696 conv
->title
= g_strdup(title
);
698 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_TITLE
);
702 purple_conversation_get_title(const PurpleConversation
*conv
)
704 g_return_val_if_fail(conv
!= NULL
, NULL
);
710 purple_conversation_autoset_title(PurpleConversation
*conv
)
712 PurpleAccount
*account
;
715 const char *text
= NULL
, *name
;
717 g_return_if_fail(conv
!= NULL
);
719 account
= purple_conversation_get_account(conv
);
720 name
= purple_conversation_get_name(conv
);
722 if(purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
) {
723 if(account
&& ((b
= purple_find_buddy(account
, name
)) != NULL
))
724 text
= purple_buddy_get_contact_alias(b
);
725 } else if(purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
) {
726 if(account
&& ((chat
= purple_blist_find_chat(account
, name
)) != NULL
))
727 text
= purple_chat_get_name(chat
);
734 purple_conversation_set_title(conv
, text
);
738 purple_conversation_foreach(void (*func
)(PurpleConversation
*conv
))
740 PurpleConversation
*conv
;
743 g_return_if_fail(func
!= NULL
);
745 for (l
= purple_get_conversations(); l
!= NULL
; l
= l
->next
) {
746 conv
= (PurpleConversation
*)l
->data
;
753 purple_conversation_set_name(PurpleConversation
*conv
, const char *name
)
755 struct _purple_hconv
*hc
;
756 g_return_if_fail(conv
!= NULL
);
758 hc
= g_new(struct _purple_hconv
, 1);
759 hc
->type
= conv
->type
;
760 hc
->account
= conv
->account
;
761 hc
->name
= (gchar
*)purple_normalize(conv
->account
, conv
->name
);
763 g_hash_table_remove(conversation_cache
, hc
);
766 conv
->name
= g_strdup(name
);
767 hc
->name
= g_strdup(purple_normalize(conv
->account
, conv
->name
));
768 g_hash_table_insert(conversation_cache
, hc
, conv
);
770 purple_conversation_autoset_title(conv
);
774 purple_conversation_get_name(const PurpleConversation
*conv
)
776 g_return_val_if_fail(conv
!= NULL
, NULL
);
782 purple_conversation_set_logging(PurpleConversation
*conv
, gboolean log
)
784 g_return_if_fail(conv
!= NULL
);
786 if (conv
->logging
!= log
)
789 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_LOGGING
);
794 purple_conversation_is_logging(const PurpleConversation
*conv
)
796 g_return_val_if_fail(conv
!= NULL
, FALSE
);
798 return conv
->logging
;
802 purple_conversation_close_logs(PurpleConversation
*conv
)
804 g_return_if_fail(conv
!= NULL
);
806 g_list_foreach(conv
->logs
, (GFunc
)purple_log_free
, NULL
);
807 g_list_free(conv
->logs
);
812 purple_conversation_get_im_data(const PurpleConversation
*conv
)
814 g_return_val_if_fail(conv
!= NULL
, NULL
);
816 if (purple_conversation_get_type(conv
) != PURPLE_CONV_TYPE_IM
)
823 purple_conversation_get_chat_data(const PurpleConversation
*conv
)
825 g_return_val_if_fail(conv
!= NULL
, NULL
);
827 if (purple_conversation_get_type(conv
) != PURPLE_CONV_TYPE_CHAT
)
834 purple_conversation_set_data(PurpleConversation
*conv
, const char *key
,
837 g_return_if_fail(conv
!= NULL
);
838 g_return_if_fail(key
!= NULL
);
840 g_hash_table_replace(conv
->data
, g_strdup(key
), data
);
844 purple_conversation_get_data(PurpleConversation
*conv
, const char *key
)
846 g_return_val_if_fail(conv
!= NULL
, NULL
);
847 g_return_val_if_fail(key
!= NULL
, NULL
);
849 return g_hash_table_lookup(conv
->data
, key
);
853 purple_get_conversations(void)
855 return conversations
;
865 purple_get_chats(void)
872 purple_find_conversation_with_account(PurpleConversationType type
,
874 const PurpleAccount
*account
)
876 PurpleConversation
*c
= NULL
;
877 struct _purple_hconv hc
;
879 g_return_val_if_fail(name
!= NULL
, NULL
);
881 hc
.name
= (gchar
*)purple_normalize(account
, name
);
882 hc
.account
= account
;
886 case PURPLE_CONV_TYPE_IM
:
887 case PURPLE_CONV_TYPE_CHAT
:
888 c
= g_hash_table_lookup(conversation_cache
, &hc
);
890 case PURPLE_CONV_TYPE_ANY
:
891 hc
.type
= PURPLE_CONV_TYPE_IM
;
892 c
= g_hash_table_lookup(conversation_cache
, &hc
);
894 hc
.type
= PURPLE_CONV_TYPE_CHAT
;
895 c
= g_hash_table_lookup(conversation_cache
, &hc
);
899 g_return_val_if_reached(NULL
);
906 purple_conversation_write(PurpleConversation
*conv
, const char *who
,
907 const char *message
, PurpleMessageFlags flags
,
910 PurplePluginProtocolInfo
*prpl_info
= NULL
;
911 PurpleConnection
*gc
= NULL
;
912 PurpleAccount
*account
;
913 PurpleConversationUiOps
*ops
;
915 char *displayed
= NULL
;
918 PurpleConversationType type
;
919 /* int logging_font_options = 0; */
921 g_return_if_fail(conv
!= NULL
);
922 g_return_if_fail(message
!= NULL
);
924 ops
= purple_conversation_get_ui_ops(conv
);
926 account
= purple_conversation_get_account(conv
);
927 type
= purple_conversation_get_type(conv
);
930 gc
= purple_account_get_connection(account
);
932 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
&&
933 (gc
!= NULL
&& !g_slist_find(gc
->buddy_chats
, conv
)))
936 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
&&
937 !g_list_find(purple_get_conversations(), conv
))
940 displayed
= g_strdup(message
);
942 if (who
== NULL
|| *who
== '\0')
943 who
= purple_conversation_get_name(conv
);
947 GPOINTER_TO_INT(purple_signal_emit_return_1(
948 purple_conversations_get_handle(),
949 (type
== PURPLE_CONV_TYPE_IM
? "writing-im-msg" : "writing-chat-msg"),
950 account
, who
, &displayed
, conv
, flags
));
952 if (displayed
== NULL
)
960 if (account
!= NULL
) {
961 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account
)));
963 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
||
964 !(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
966 if (flags
& PURPLE_MESSAGE_SEND
) {
967 b
= purple_find_buddy(account
,
968 purple_account_get_username(account
));
970 if (purple_account_get_alias(account
) != NULL
)
971 alias
= account
->alias
;
972 else if (b
!= NULL
&& !purple_strequal(purple_buddy_get_name(b
), purple_buddy_get_contact_alias(b
)))
973 alias
= purple_buddy_get_contact_alias(b
);
974 else if (purple_connection_get_display_name(gc
) != NULL
)
975 alias
= purple_connection_get_display_name(gc
);
977 alias
= purple_account_get_username(account
);
981 b
= purple_find_buddy(account
, who
);
984 alias
= purple_buddy_get_contact_alias(b
);
989 if (!(flags
& PURPLE_MESSAGE_NO_LOG
) && purple_conversation_is_logging(conv
)) {
992 if (conv
->logs
== NULL
)
996 while (log
!= NULL
) {
997 purple_log_write((PurpleLog
*)log
->data
, flags
, alias
, mtime
, displayed
);
1002 if (ops
&& ops
->write_conv
)
1003 ops
->write_conv(conv
, who
, alias
, displayed
, flags
, mtime
);
1005 add_message_to_history(conv
, who
, alias
, message
, flags
, mtime
);
1007 purple_signal_emit(purple_conversations_get_handle(),
1008 (type
== PURPLE_CONV_TYPE_IM
? "wrote-im-msg" : "wrote-chat-msg"),
1009 account
, who
, displayed
, conv
, flags
);
1015 purple_conversation_has_focus(PurpleConversation
*conv
)
1017 gboolean ret
= FALSE
;
1018 PurpleConversationUiOps
*ops
;
1020 g_return_val_if_fail(conv
!= NULL
, FALSE
);
1022 ops
= purple_conversation_get_ui_ops(conv
);
1024 if (ops
!= NULL
&& ops
->has_focus
!= NULL
)
1025 ret
= ops
->has_focus(conv
);
1031 * TODO: Need to make sure calls to this function happen in the core
1032 * instead of the UI. That way UIs have less work to do, and the
1033 * core/UI split is cleaner. Also need to make sure this is called
1034 * when chats are added/removed from the blist.
1037 purple_conversation_update(PurpleConversation
*conv
, PurpleConvUpdateType type
)
1039 g_return_if_fail(conv
!= NULL
);
1041 purple_signal_emit(purple_conversations_get_handle(),
1042 "conversation-updated", conv
, type
);
1045 /**************************************************************************
1046 * IM Conversation API
1047 **************************************************************************/
1048 PurpleConversation
*
1049 purple_conv_im_get_conversation(const PurpleConvIm
*im
)
1051 g_return_val_if_fail(im
!= NULL
, NULL
);
1057 purple_conv_im_set_icon(PurpleConvIm
*im
, PurpleBuddyIcon
*icon
)
1059 g_return_if_fail(im
!= NULL
);
1061 if (im
->icon
!= icon
)
1063 purple_buddy_icon_unref(im
->icon
);
1065 im
->icon
= (icon
== NULL
? NULL
: purple_buddy_icon_ref(icon
));
1068 purple_conversation_update(purple_conv_im_get_conversation(im
),
1069 PURPLE_CONV_UPDATE_ICON
);
1073 purple_conv_im_get_icon(const PurpleConvIm
*im
)
1075 g_return_val_if_fail(im
!= NULL
, NULL
);
1081 purple_conv_im_set_typing_state(PurpleConvIm
*im
, PurpleTypingState state
)
1083 g_return_if_fail(im
!= NULL
);
1085 if (im
->typing_state
!= state
)
1087 im
->typing_state
= state
;
1092 purple_signal_emit(purple_conversations_get_handle(),
1093 "buddy-typing", im
->conv
->account
, im
->conv
->name
);
1096 purple_signal_emit(purple_conversations_get_handle(),
1097 "buddy-typed", im
->conv
->account
, im
->conv
->name
);
1099 case PURPLE_NOT_TYPING
:
1100 purple_signal_emit(purple_conversations_get_handle(),
1101 "buddy-typing-stopped", im
->conv
->account
, im
->conv
->name
);
1105 purple_conv_im_update_typing(im
);
1110 purple_conv_im_get_typing_state(const PurpleConvIm
*im
)
1112 g_return_val_if_fail(im
!= NULL
, 0);
1114 return im
->typing_state
;
1118 purple_conv_im_start_typing_timeout(PurpleConvIm
*im
, int timeout
)
1120 PurpleConversation
*conv
;
1122 g_return_if_fail(im
!= NULL
);
1124 if (im
->typing_timeout
> 0)
1125 purple_conv_im_stop_typing_timeout(im
);
1127 conv
= purple_conv_im_get_conversation(im
);
1129 im
->typing_timeout
= purple_timeout_add_seconds(timeout
, reset_typing_cb
, conv
);
1133 purple_conv_im_stop_typing_timeout(PurpleConvIm
*im
)
1135 g_return_if_fail(im
!= NULL
);
1137 if (im
->typing_timeout
== 0)
1140 purple_timeout_remove(im
->typing_timeout
);
1141 im
->typing_timeout
= 0;
1145 purple_conv_im_get_typing_timeout(const PurpleConvIm
*im
)
1147 g_return_val_if_fail(im
!= NULL
, 0);
1149 return im
->typing_timeout
;
1153 purple_conv_im_set_type_again(PurpleConvIm
*im
, unsigned int val
)
1155 g_return_if_fail(im
!= NULL
);
1160 im
->type_again
= time(NULL
) + val
;
1164 purple_conv_im_get_type_again(const PurpleConvIm
*im
)
1166 g_return_val_if_fail(im
!= NULL
, 0);
1168 return im
->type_again
;
1172 purple_conv_im_start_send_typed_timeout(PurpleConvIm
*im
)
1174 g_return_if_fail(im
!= NULL
);
1176 im
->send_typed_timeout
= purple_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS
,
1178 purple_conv_im_get_conversation(im
));
1182 purple_conv_im_stop_send_typed_timeout(PurpleConvIm
*im
)
1184 g_return_if_fail(im
!= NULL
);
1186 if (im
->send_typed_timeout
== 0)
1189 purple_timeout_remove(im
->send_typed_timeout
);
1190 im
->send_typed_timeout
= 0;
1194 purple_conv_im_get_send_typed_timeout(const PurpleConvIm
*im
)
1196 g_return_val_if_fail(im
!= NULL
, 0);
1198 return im
->send_typed_timeout
;
1202 purple_conv_im_update_typing(PurpleConvIm
*im
)
1204 g_return_if_fail(im
!= NULL
);
1206 purple_conversation_update(purple_conv_im_get_conversation(im
),
1207 PURPLE_CONV_UPDATE_TYPING
);
1211 purple_conv_im_write(PurpleConvIm
*im
, const char *who
, const char *message
,
1212 PurpleMessageFlags flags
, time_t mtime
)
1214 PurpleConversation
*c
;
1216 g_return_if_fail(im
!= NULL
);
1217 g_return_if_fail(message
!= NULL
);
1219 c
= purple_conv_im_get_conversation(im
);
1221 if ((flags
& PURPLE_MESSAGE_RECV
) == PURPLE_MESSAGE_RECV
) {
1222 purple_conv_im_set_typing_state(im
, PURPLE_NOT_TYPING
);
1225 /* Pass this on to either the ops structure or the default write func. */
1226 if (c
->ui_ops
!= NULL
&& c
->ui_ops
->write_im
!= NULL
)
1227 c
->ui_ops
->write_im(c
, who
, message
, flags
, mtime
);
1229 purple_conversation_write(c
, who
, message
, flags
, mtime
);
1232 gboolean
purple_conv_present_error(const char *who
, PurpleAccount
*account
, const char *what
)
1234 PurpleConversation
*conv
;
1236 g_return_val_if_fail(who
!= NULL
, FALSE
);
1237 g_return_val_if_fail(account
!=NULL
, FALSE
);
1238 g_return_val_if_fail(what
!= NULL
, FALSE
);
1240 conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY
, who
, account
);
1242 purple_conversation_write(conv
, NULL
, what
, PURPLE_MESSAGE_ERROR
, time(NULL
));
1250 purple_conv_im_send(PurpleConvIm
*im
, const char *message
)
1252 purple_conv_im_send_with_flags(im
, message
, 0);
1256 purple_conv_send_confirm_cb(gpointer
*data
)
1258 PurpleConversation
*conv
= data
[0];
1259 char *message
= data
[1];
1262 common_send(conv
, message
, 0);
1266 purple_conv_send_confirm(PurpleConversation
*conv
, const char *message
)
1271 g_return_if_fail(conv
!= NULL
);
1272 g_return_if_fail(message
!= NULL
);
1274 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->send_confirm
!= NULL
)
1276 conv
->ui_ops
->send_confirm(conv
, message
);
1280 text
= g_strdup_printf("You are about to send the following message:\n%s", message
);
1281 data
= g_new0(gpointer
, 2);
1283 data
[1] = (gpointer
)message
;
1285 purple_request_action(conv
, NULL
, _("Send Message"), text
, 0,
1286 purple_conversation_get_account(conv
), NULL
, conv
,
1288 _("_Send Message"), G_CALLBACK(purple_conv_send_confirm_cb
),
1293 purple_conv_im_send_with_flags(PurpleConvIm
*im
, const char *message
, PurpleMessageFlags flags
)
1295 g_return_if_fail(im
!= NULL
);
1296 g_return_if_fail(message
!= NULL
);
1298 common_send(purple_conv_im_get_conversation(im
), message
, flags
);
1302 purple_conv_custom_smiley_add(PurpleConversation
*conv
, const char *smile
,
1303 const char *cksum_type
, const char *chksum
,
1306 if (conv
== NULL
|| smile
== NULL
|| !*smile
) {
1310 /* TODO: check if the icon is in the cache and return false if so */
1311 /* TODO: add an icon cache (that doesn't suck) */
1312 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->custom_smiley_add
!=NULL
) {
1313 return conv
->ui_ops
->custom_smiley_add(conv
, smile
, remote
);
1315 purple_debug_info("conversation", "Could not find add custom smiley function");
1322 purple_conv_custom_smiley_write(PurpleConversation
*conv
, const char *smile
,
1323 const guchar
*data
, gsize size
)
1325 g_return_if_fail(conv
!= NULL
);
1326 g_return_if_fail(smile
!= NULL
&& *smile
);
1328 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->custom_smiley_write
!= NULL
)
1329 conv
->ui_ops
->custom_smiley_write(conv
, smile
, data
, size
);
1331 purple_debug_info("conversation", "Could not find the smiley write function");
1335 purple_conv_custom_smiley_close(PurpleConversation
*conv
, const char *smile
)
1337 g_return_if_fail(conv
!= NULL
);
1338 g_return_if_fail(smile
!= NULL
&& *smile
);
1340 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->custom_smiley_close
!= NULL
)
1341 conv
->ui_ops
->custom_smiley_close(conv
, smile
);
1343 purple_debug_info("conversation", "Could not find custom smiley close function");
1347 /**************************************************************************
1348 * Chat Conversation API
1349 **************************************************************************/
1351 PurpleConversation
*
1352 purple_conv_chat_get_conversation(const PurpleConvChat
*chat
)
1354 g_return_val_if_fail(chat
!= NULL
, NULL
);
1360 purple_conv_chat_set_users(PurpleConvChat
*chat
, GList
*users
)
1362 g_return_val_if_fail(chat
!= NULL
, NULL
);
1364 chat
->in_room
= users
;
1370 purple_conv_chat_get_users(const PurpleConvChat
*chat
)
1372 g_return_val_if_fail(chat
!= NULL
, NULL
);
1374 return chat
->in_room
;
1378 purple_conv_chat_ignore(PurpleConvChat
*chat
, const char *name
)
1380 g_return_if_fail(chat
!= NULL
);
1381 g_return_if_fail(name
!= NULL
);
1383 /* Make sure the user isn't already ignored. */
1384 if (purple_conv_chat_is_user_ignored(chat
, name
))
1387 purple_conv_chat_set_ignored(chat
,
1388 g_list_append(chat
->ignored
, g_strdup(name
)));
1392 purple_conv_chat_unignore(PurpleConvChat
*chat
, const char *name
)
1396 g_return_if_fail(chat
!= NULL
);
1397 g_return_if_fail(name
!= NULL
);
1399 /* Make sure the user is actually ignored. */
1400 if (!purple_conv_chat_is_user_ignored(chat
, name
))
1403 item
= g_list_find(purple_conv_chat_get_ignored(chat
),
1404 purple_conv_chat_get_ignored_user(chat
, name
));
1406 purple_conv_chat_set_ignored(chat
,
1407 g_list_remove_link(chat
->ignored
, item
));
1410 g_list_free_1(item
);
1414 purple_conv_chat_set_ignored(PurpleConvChat
*chat
, GList
*ignored
)
1416 g_return_val_if_fail(chat
!= NULL
, NULL
);
1418 chat
->ignored
= ignored
;
1424 purple_conv_chat_get_ignored(const PurpleConvChat
*chat
)
1426 g_return_val_if_fail(chat
!= NULL
, NULL
);
1428 return chat
->ignored
;
1432 purple_conv_chat_get_ignored_user(const PurpleConvChat
*chat
, const char *user
)
1436 g_return_val_if_fail(chat
!= NULL
, NULL
);
1437 g_return_val_if_fail(user
!= NULL
, NULL
);
1439 for (ignored
= purple_conv_chat_get_ignored(chat
);
1441 ignored
= ignored
->next
) {
1443 const char *ign
= (const char *)ignored
->data
;
1445 if (!purple_utf8_strcasecmp(user
, ign
) ||
1446 ((*ign
== '+' || *ign
== '%') && !purple_utf8_strcasecmp(user
, ign
+ 1)))
1452 if ((*ign
== '+' && !purple_utf8_strcasecmp(user
, ign
+ 1)) ||
1453 (*ign
!= '+' && !purple_utf8_strcasecmp(user
, ign
)))
1462 purple_conv_chat_is_user_ignored(const PurpleConvChat
*chat
, const char *user
)
1464 g_return_val_if_fail(chat
!= NULL
, FALSE
);
1465 g_return_val_if_fail(user
!= NULL
, FALSE
);
1467 return (purple_conv_chat_get_ignored_user(chat
, user
) != NULL
);
1471 purple_conv_chat_set_topic(PurpleConvChat
*chat
, const char *who
, const char *topic
)
1473 g_return_if_fail(chat
!= NULL
);
1476 g_free(chat
->topic
);
1478 chat
->who
= g_strdup(who
);
1479 chat
->topic
= g_strdup(topic
);
1481 purple_conversation_update(purple_conv_chat_get_conversation(chat
),
1482 PURPLE_CONV_UPDATE_TOPIC
);
1484 purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed",
1485 chat
->conv
, chat
->who
, chat
->topic
);
1489 purple_conv_chat_get_topic(const PurpleConvChat
*chat
)
1491 g_return_val_if_fail(chat
!= NULL
, NULL
);
1497 purple_conv_chat_set_id(PurpleConvChat
*chat
, int id
)
1499 g_return_if_fail(chat
!= NULL
);
1505 purple_conv_chat_get_id(const PurpleConvChat
*chat
)
1507 g_return_val_if_fail(chat
!= NULL
, -1);
1513 purple_conv_chat_write(PurpleConvChat
*chat
, const char *who
, const char *message
,
1514 PurpleMessageFlags flags
, time_t mtime
)
1516 PurpleAccount
*account
;
1517 PurpleConversation
*conv
;
1518 PurpleConnection
*gc
;
1520 g_return_if_fail(chat
!= NULL
);
1521 g_return_if_fail(who
!= NULL
);
1522 g_return_if_fail(message
!= NULL
);
1524 conv
= purple_conv_chat_get_conversation(chat
);
1525 gc
= purple_conversation_get_gc(conv
);
1526 account
= purple_connection_get_account(gc
);
1528 /* Don't display this if the person who wrote it is ignored. */
1529 if (purple_conv_chat_is_user_ignored(chat
, who
))
1532 if (!(flags
& PURPLE_MESSAGE_WHISPER
)) {
1535 str
= purple_normalize(account
, who
);
1537 if (purple_strequal(str
, chat
->nick
)) {
1538 flags
|= PURPLE_MESSAGE_SEND
;
1540 flags
|= PURPLE_MESSAGE_RECV
;
1542 if (purple_utf8_has_word(message
, chat
->nick
))
1543 flags
|= PURPLE_MESSAGE_NICK
;
1547 /* Pass this on to either the ops structure or the default write func. */
1548 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->write_chat
!= NULL
)
1549 conv
->ui_ops
->write_chat(conv
, who
, message
, flags
, mtime
);
1551 purple_conversation_write(conv
, who
, message
, flags
, mtime
);
1555 purple_conv_chat_send(PurpleConvChat
*chat
, const char *message
)
1557 purple_conv_chat_send_with_flags(chat
, message
, 0);
1561 purple_conv_chat_send_with_flags(PurpleConvChat
*chat
, const char *message
, PurpleMessageFlags flags
)
1563 g_return_if_fail(chat
!= NULL
);
1564 g_return_if_fail(message
!= NULL
);
1566 common_send(purple_conv_chat_get_conversation(chat
), message
, flags
);
1570 purple_conv_chat_add_user(PurpleConvChat
*chat
, const char *user
,
1571 const char *extra_msg
, PurpleConvChatBuddyFlags flags
,
1572 gboolean new_arrival
)
1574 GList
*users
= g_list_append(NULL
, (char *)user
);
1575 GList
*extra_msgs
= g_list_append(NULL
, (char *)extra_msg
);
1576 GList
*flags2
= g_list_append(NULL
, GINT_TO_POINTER(flags
));
1578 purple_conv_chat_add_users(chat
, users
, extra_msgs
, flags2
, new_arrival
);
1581 g_list_free(extra_msgs
);
1582 g_list_free(flags2
);
1586 purple_conv_chat_cb_compare(PurpleConvChatBuddy
*a
, PurpleConvChatBuddy
*b
)
1588 PurpleConvChatBuddyFlags f1
= 0, f2
= 0;
1589 char *user1
= NULL
, *user2
= NULL
;
1595 user1
= a
->alias_key
;
1603 user2
= b
->alias_key
;
1608 if (user1
== NULL
|| user2
== NULL
) {
1609 if (!(user1
== NULL
&& user2
== NULL
))
1610 ret
= (user1
== NULL
) ? -1: 1;
1611 } else if (f1
!= f2
) {
1612 /* sort more important users first */
1613 ret
= (f1
> f2
) ? -1 : 1;
1614 } else if (a
->buddy
!= b
->buddy
) {
1615 ret
= a
->buddy
? -1 : 1;
1617 ret
= purple_utf8_strcasecmp(user1
, user2
);
1624 purple_conv_chat_add_users(PurpleConvChat
*chat
, GList
*users
, GList
*extra_msgs
,
1625 GList
*flags
, gboolean new_arrivals
)
1627 PurpleConversation
*conv
;
1628 PurpleConversationUiOps
*ops
;
1629 PurpleConvChatBuddy
*cbuddy
;
1630 PurpleConnection
*gc
;
1631 PurplePluginProtocolInfo
*prpl_info
;
1633 GList
*cbuddies
= NULL
;
1635 g_return_if_fail(chat
!= NULL
);
1636 g_return_if_fail(users
!= NULL
);
1638 conv
= purple_conv_chat_get_conversation(chat
);
1639 ops
= purple_conversation_get_ui_ops(conv
);
1641 gc
= purple_conversation_get_gc(conv
);
1642 g_return_if_fail(gc
!= NULL
);
1643 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1644 g_return_if_fail(prpl_info
!= NULL
);
1648 while ((ul
!= NULL
) && (fl
!= NULL
)) {
1649 const char *user
= (const char *)ul
->data
;
1650 const char *alias
= user
;
1652 PurpleConvChatBuddyFlags flag
= GPOINTER_TO_INT(fl
->data
);
1653 const char *extra_msg
= (extra_msgs
? extra_msgs
->data
: NULL
);
1655 if(!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1656 if (purple_strequal(chat
->nick
, purple_normalize(conv
->account
, user
))) {
1657 const char *alias2
= purple_account_get_alias(conv
->account
);
1662 const char *display_name
= purple_connection_get_display_name(gc
);
1663 if (display_name
!= NULL
)
1664 alias
= display_name
;
1668 if ((buddy
= purple_find_buddy(gc
->account
, user
)) != NULL
)
1669 alias
= purple_buddy_get_contact_alias(buddy
);
1673 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
1674 "chat-buddy-joining", conv
, user
, flag
)) ||
1675 purple_conv_chat_is_user_ignored(chat
, user
);
1677 cbuddy
= purple_conv_chat_cb_new(user
, alias
, flag
);
1678 cbuddy
->buddy
= purple_find_buddy(conv
->account
, user
) != NULL
;
1679 /* This seems dumb. Why should we set users thousands of times? */
1680 purple_conv_chat_set_users(chat
,
1681 g_list_prepend(chat
->in_room
, cbuddy
));
1683 cbuddies
= g_list_prepend(cbuddies
, cbuddy
);
1685 if (!quiet
&& new_arrivals
) {
1686 char *alias_esc
= g_markup_escape_text(alias
, -1);
1689 if (extra_msg
== NULL
)
1690 tmp
= g_strdup_printf(_("%s entered the room."), alias_esc
);
1692 char *extra_msg_esc
= g_markup_escape_text(extra_msg
, -1);
1693 tmp
= g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
1694 alias_esc
, extra_msg_esc
);
1695 g_free(extra_msg_esc
);
1699 purple_conversation_write(conv
, NULL
, tmp
,
1700 PURPLE_MESSAGE_SYSTEM
| PURPLE_MESSAGE_NO_LINKIFY
,
1705 purple_signal_emit(purple_conversations_get_handle(),
1706 "chat-buddy-joined", conv
, user
, flag
, new_arrivals
);
1709 if (extra_msgs
!= NULL
)
1710 extra_msgs
= extra_msgs
->next
;
1713 cbuddies
= g_list_sort(cbuddies
, (GCompareFunc
)purple_conv_chat_cb_compare
);
1715 if (ops
!= NULL
&& ops
->chat_add_users
!= NULL
)
1716 ops
->chat_add_users(conv
, cbuddies
, new_arrivals
);
1718 g_list_free(cbuddies
);
1722 purple_conv_chat_rename_user(PurpleConvChat
*chat
, const char *old_user
,
1723 const char *new_user
)
1725 PurpleConversation
*conv
;
1726 PurpleConversationUiOps
*ops
;
1727 PurpleConnection
*gc
;
1728 PurplePluginProtocolInfo
*prpl_info
;
1729 PurpleConvChatBuddy
*cb
;
1730 PurpleConvChatBuddyFlags flags
;
1731 const char *new_alias
= new_user
;
1733 gboolean is_me
= FALSE
;
1735 g_return_if_fail(chat
!= NULL
);
1736 g_return_if_fail(old_user
!= NULL
);
1737 g_return_if_fail(new_user
!= NULL
);
1739 conv
= purple_conv_chat_get_conversation(chat
);
1740 ops
= purple_conversation_get_ui_ops(conv
);
1742 gc
= purple_conversation_get_gc(conv
);
1743 g_return_if_fail(gc
!= NULL
);
1744 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1745 g_return_if_fail(prpl_info
!= NULL
);
1747 if (purple_strequal(chat
->nick
, purple_normalize(conv
->account
, old_user
))) {
1750 /* Note this for later. */
1753 if(!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1754 alias
= purple_account_get_alias(conv
->account
);
1759 const char *display_name
= purple_connection_get_display_name(gc
);
1760 if (display_name
!= NULL
)
1761 alias
= display_name
;
1764 } else if (!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1766 if ((buddy
= purple_find_buddy(gc
->account
, new_user
)) != NULL
)
1767 new_alias
= purple_buddy_get_contact_alias(buddy
);
1770 flags
= purple_conv_chat_user_get_flags(chat
, old_user
);
1771 cb
= purple_conv_chat_cb_new(new_user
, new_alias
, flags
);
1772 cb
->buddy
= purple_find_buddy(conv
->account
, new_user
) != NULL
;
1773 purple_conv_chat_set_users(chat
,
1774 g_list_prepend(chat
->in_room
, cb
));
1776 if (ops
!= NULL
&& ops
->chat_rename_user
!= NULL
)
1777 ops
->chat_rename_user(conv
, old_user
, new_user
, new_alias
);
1779 cb
= purple_conv_chat_cb_find(chat
, old_user
);
1782 purple_conv_chat_set_users(chat
,
1783 g_list_remove(chat
->in_room
, cb
));
1784 purple_conv_chat_cb_destroy(cb
);
1787 if (purple_conv_chat_is_user_ignored(chat
, old_user
)) {
1788 purple_conv_chat_unignore(chat
, old_user
);
1789 purple_conv_chat_ignore(chat
, new_user
);
1791 else if (purple_conv_chat_is_user_ignored(chat
, new_user
))
1792 purple_conv_chat_unignore(chat
, new_user
);
1795 purple_conv_chat_set_nick(chat
, new_user
);
1797 if (purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") &&
1798 !purple_conv_chat_is_user_ignored(chat
, new_user
)) {
1801 char *escaped
= g_markup_escape_text(new_user
, -1);
1802 g_snprintf(tmp
, sizeof(tmp
),
1803 _("You are now known as %s"), escaped
);
1806 const char *old_alias
= old_user
;
1807 const char *new_alias
= new_user
;
1811 if (!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1814 if ((buddy
= purple_find_buddy(gc
->account
, old_user
)) != NULL
)
1815 old_alias
= purple_buddy_get_contact_alias(buddy
);
1816 if ((buddy
= purple_find_buddy(gc
->account
, new_user
)) != NULL
)
1817 new_alias
= purple_buddy_get_contact_alias(buddy
);
1820 escaped
= g_markup_escape_text(old_alias
, -1);
1821 escaped2
= g_markup_escape_text(new_alias
, -1);
1822 g_snprintf(tmp
, sizeof(tmp
),
1823 _("%s is now known as %s"), escaped
, escaped2
);
1828 purple_conversation_write(conv
, NULL
, tmp
,
1829 PURPLE_MESSAGE_SYSTEM
| PURPLE_MESSAGE_NO_LINKIFY
,
1835 purple_conv_chat_remove_user(PurpleConvChat
*chat
, const char *user
, const char *reason
)
1837 GList
*users
= g_list_append(NULL
, (char *)user
);
1839 purple_conv_chat_remove_users(chat
, users
, reason
);
1845 purple_conv_chat_remove_users(PurpleConvChat
*chat
, GList
*users
, const char *reason
)
1847 PurpleConversation
*conv
;
1848 PurpleConnection
*gc
;
1849 PurplePluginProtocolInfo
*prpl_info
;
1850 PurpleConversationUiOps
*ops
;
1851 PurpleConvChatBuddy
*cb
;
1855 g_return_if_fail(chat
!= NULL
);
1856 g_return_if_fail(users
!= NULL
);
1858 conv
= purple_conv_chat_get_conversation(chat
);
1860 gc
= purple_conversation_get_gc(conv
);
1861 g_return_if_fail(gc
!= NULL
);
1862 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1863 g_return_if_fail(prpl_info
!= NULL
);
1865 ops
= purple_conversation_get_ui_ops(conv
);
1867 for (l
= users
; l
!= NULL
; l
= l
->next
) {
1868 const char *user
= (const char *)l
->data
;
1869 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
1870 "chat-buddy-leaving", conv
, user
, reason
)) |
1871 purple_conv_chat_is_user_ignored(chat
, user
);
1873 cb
= purple_conv_chat_cb_find(chat
, user
);
1876 purple_conv_chat_set_users(chat
,
1877 g_list_remove(chat
->in_room
, cb
));
1878 purple_conv_chat_cb_destroy(cb
);
1881 /* NOTE: Don't remove them from ignored in case they re-enter. */
1884 const char *alias
= user
;
1888 if (!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1891 if ((buddy
= purple_find_buddy(gc
->account
, user
)) != NULL
)
1892 alias
= purple_buddy_get_contact_alias(buddy
);
1895 alias_esc
= g_markup_escape_text(alias
, -1);
1897 if (reason
== NULL
|| !*reason
)
1898 tmp
= g_strdup_printf(_("%s left the room."), alias_esc
);
1900 char *reason_esc
= g_markup_escape_text(reason
, -1);
1901 tmp
= g_strdup_printf(_("%s left the room (%s)."),
1902 alias_esc
, reason_esc
);
1907 purple_conversation_write(conv
, NULL
, tmp
,
1908 PURPLE_MESSAGE_SYSTEM
| PURPLE_MESSAGE_NO_LINKIFY
,
1913 purple_signal_emit(purple_conversations_get_handle(), "chat-buddy-left",
1914 conv
, user
, reason
);
1917 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
)
1918 ops
->chat_remove_users(conv
, users
);
1922 purple_conv_chat_clear_users(PurpleConvChat
*chat
)
1924 PurpleConversation
*conv
;
1925 PurpleConversationUiOps
*ops
;
1928 GList
*names
= NULL
;
1930 g_return_if_fail(chat
!= NULL
);
1932 conv
= purple_conv_chat_get_conversation(chat
);
1933 ops
= purple_conversation_get_ui_ops(conv
);
1934 users
= chat
->in_room
;
1936 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
) {
1937 for (l
= users
; l
; l
= l
->next
) {
1938 PurpleConvChatBuddy
*cb
= l
->data
;
1939 names
= g_list_prepend(names
, cb
->name
);
1941 ops
->chat_remove_users(conv
, names
);
1945 for (l
= users
; l
; l
= l
->next
)
1947 PurpleConvChatBuddy
*cb
= l
->data
;
1949 purple_signal_emit(purple_conversations_get_handle(),
1950 "chat-buddy-leaving", conv
, cb
->name
, NULL
);
1951 purple_signal_emit(purple_conversations_get_handle(),
1952 "chat-buddy-left", conv
, cb
->name
, NULL
);
1954 purple_conv_chat_cb_destroy(cb
);
1958 purple_conv_chat_set_users(chat
, NULL
);
1963 purple_conv_chat_find_user(PurpleConvChat
*chat
, const char *user
)
1965 g_return_val_if_fail(chat
!= NULL
, FALSE
);
1966 g_return_val_if_fail(user
!= NULL
, FALSE
);
1968 return (purple_conv_chat_cb_find(chat
, user
) != NULL
);
1972 purple_conv_chat_user_set_flags(PurpleConvChat
*chat
, const char *user
,
1973 PurpleConvChatBuddyFlags flags
)
1975 PurpleConversation
*conv
;
1976 PurpleConversationUiOps
*ops
;
1977 PurpleConvChatBuddy
*cb
;
1978 PurpleConvChatBuddyFlags oldflags
;
1980 g_return_if_fail(chat
!= NULL
);
1981 g_return_if_fail(user
!= NULL
);
1983 cb
= purple_conv_chat_cb_find(chat
, user
);
1988 if (flags
== cb
->flags
)
1991 oldflags
= cb
->flags
;
1994 conv
= purple_conv_chat_get_conversation(chat
);
1995 ops
= purple_conversation_get_ui_ops(conv
);
1997 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
1998 ops
->chat_update_user(conv
, user
);
2000 purple_signal_emit(purple_conversations_get_handle(),
2001 "chat-buddy-flags", conv
, user
, oldflags
, flags
);
2004 PurpleConvChatBuddyFlags
2005 purple_conv_chat_user_get_flags(PurpleConvChat
*chat
, const char *user
)
2007 PurpleConvChatBuddy
*cb
;
2009 g_return_val_if_fail(chat
!= NULL
, 0);
2010 g_return_val_if_fail(user
!= NULL
, 0);
2012 cb
= purple_conv_chat_cb_find(chat
, user
);
2015 return PURPLE_CBFLAGS_NONE
;
2020 void purple_conv_chat_set_nick(PurpleConvChat
*chat
, const char *nick
) {
2021 g_return_if_fail(chat
!= NULL
);
2024 chat
->nick
= g_strdup(purple_normalize(chat
->conv
->account
, nick
));
2027 const char *purple_conv_chat_get_nick(PurpleConvChat
*chat
) {
2028 g_return_val_if_fail(chat
!= NULL
, NULL
);
2033 PurpleConversation
*
2034 purple_find_chat(const PurpleConnection
*gc
, int id
)
2037 PurpleConversation
*conv
;
2039 for (l
= purple_get_chats(); l
!= NULL
; l
= l
->next
) {
2040 conv
= (PurpleConversation
*)l
->data
;
2042 if (purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv
)) == id
&&
2043 purple_conversation_get_gc(conv
) == gc
)
2051 purple_conv_chat_left(PurpleConvChat
*chat
)
2053 g_return_if_fail(chat
!= NULL
);
2056 purple_conversation_update(chat
->conv
, PURPLE_CONV_UPDATE_CHATLEFT
);
2060 invite_user_to_chat(gpointer data
, PurpleRequestFields
*fields
)
2062 PurpleConversation
*conv
;
2063 PurpleConvChat
*chat
;
2064 const char *user
, *message
;
2067 chat
= PURPLE_CONV_CHAT(conv
);
2068 user
= purple_request_fields_get_string(fields
, "screenname");
2069 message
= purple_request_fields_get_string(fields
, "message");
2071 serv_chat_invite(purple_conversation_get_gc(conv
), chat
->id
, message
, user
);
2074 void purple_conv_chat_invite_user(PurpleConvChat
*chat
, const char *user
,
2075 const char *message
, gboolean confirm
)
2077 PurpleAccount
*account
;
2078 PurpleConversation
*conv
;
2079 PurpleRequestFields
*fields
;
2080 PurpleRequestFieldGroup
*group
;
2081 PurpleRequestField
*field
;
2083 g_return_if_fail(chat
);
2085 if (!user
|| !*user
|| !message
|| !*message
)
2089 account
= conv
->account
;
2092 serv_chat_invite(purple_account_get_connection(account
),
2093 purple_conv_chat_get_id(chat
), message
, user
);
2097 fields
= purple_request_fields_new();
2098 group
= purple_request_field_group_new(_("Invite to chat"));
2099 purple_request_fields_add_group(fields
, group
);
2101 field
= purple_request_field_string_new("screenname", _("Buddy"), user
, FALSE
);
2102 purple_request_field_group_add_field(group
, field
);
2103 purple_request_field_set_required(field
, TRUE
);
2104 purple_request_field_set_type_hint(field
, "screenname");
2106 field
= purple_request_field_string_new("message", _("Message"), message
, FALSE
);
2107 purple_request_field_group_add_field(group
, field
);
2109 purple_request_fields(conv
, _("Invite to chat"), NULL
,
2110 _("Please enter the name of the user you wish to invite, "
2111 "along with an optional invite message."),
2113 _("Invite"), G_CALLBACK(invite_user_to_chat
),
2115 account
, user
, conv
,
2120 purple_conv_chat_has_left(PurpleConvChat
*chat
)
2122 g_return_val_if_fail(chat
!= NULL
, TRUE
);
2127 PurpleConvChatBuddy
*
2128 purple_conv_chat_cb_new(const char *name
, const char *alias
, PurpleConvChatBuddyFlags flags
)
2130 PurpleConvChatBuddy
*cb
;
2132 g_return_val_if_fail(name
!= NULL
, NULL
);
2134 cb
= g_new0(PurpleConvChatBuddy
, 1);
2135 cb
->name
= g_strdup(name
);
2137 cb
->alias
= g_strdup(alias
);
2138 cb
->attributes
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
2141 PURPLE_DBUS_REGISTER_POINTER(cb
, PurpleConvChatBuddy
);
2145 PurpleConvChatBuddy
*
2146 purple_conv_chat_cb_find(PurpleConvChat
*chat
, const char *name
)
2149 PurpleConvChatBuddy
*cb
= NULL
;
2151 g_return_val_if_fail(chat
!= NULL
, NULL
);
2152 g_return_val_if_fail(name
!= NULL
, NULL
);
2154 for (l
= purple_conv_chat_get_users(chat
); l
; l
= l
->next
) {
2156 if (!g_utf8_collate(cb
->name
, name
))
2164 purple_conv_chat_cb_destroy(PurpleConvChatBuddy
*cb
)
2170 g_free(cb
->alias_key
);
2172 g_hash_table_destroy(cb
->attributes
);
2174 PURPLE_DBUS_UNREGISTER_POINTER(cb
);
2179 purple_conv_chat_cb_get_name(PurpleConvChatBuddy
*cb
)
2181 g_return_val_if_fail(cb
!= NULL
, NULL
);
2187 purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy
*cb
, const char *key
)
2189 g_return_val_if_fail(cb
!= NULL
, NULL
);
2190 g_return_val_if_fail(key
!= NULL
, NULL
);
2192 return g_hash_table_lookup(cb
->attributes
, key
);
2196 append_attribute_key(gpointer key
, gpointer value
, gpointer user_data
)
2198 GList
**list
= user_data
;
2199 *list
= g_list_prepend(*list
, key
);
2203 purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy
*cb
)
2207 g_return_val_if_fail(cb
!= NULL
, NULL
);
2209 g_hash_table_foreach(cb
->attributes
, (GHFunc
)append_attribute_key
, &keys
);
2215 purple_conv_chat_cb_set_attribute(PurpleConvChat
*chat
, PurpleConvChatBuddy
*cb
, const char *key
, const char *value
)
2217 PurpleConversation
*conv
;
2218 PurpleConversationUiOps
*ops
;
2220 g_return_if_fail(cb
!= NULL
);
2221 g_return_if_fail(key
!= NULL
);
2222 g_return_if_fail(value
!= NULL
);
2224 g_hash_table_replace(cb
->attributes
, g_strdup(key
), g_strdup(value
));
2226 conv
= purple_conv_chat_get_conversation(chat
);
2227 ops
= purple_conversation_get_ui_ops(conv
);
2229 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
2230 ops
->chat_update_user(conv
, cb
->name
);
2234 purple_conv_chat_cb_set_attributes(PurpleConvChat
*chat
, PurpleConvChatBuddy
*cb
, GList
*keys
, GList
*values
)
2236 PurpleConversation
*conv
;
2237 PurpleConversationUiOps
*ops
;
2239 g_return_if_fail(cb
!= NULL
);
2240 g_return_if_fail(keys
!= NULL
);
2241 g_return_if_fail(values
!= NULL
);
2243 while (keys
!= NULL
&& values
!= NULL
) {
2244 g_hash_table_replace(cb
->attributes
, g_strdup(keys
->data
), g_strdup(values
->data
));
2245 keys
= g_list_next(keys
);
2246 values
= g_list_next(values
);
2249 conv
= purple_conv_chat_get_conversation(chat
);
2250 ops
= purple_conversation_get_ui_ops(conv
);
2252 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
2253 ops
->chat_update_user(conv
, cb
->name
);
2257 purple_conversation_get_extended_menu(PurpleConversation
*conv
)
2261 g_return_val_if_fail(conv
!= NULL
, NULL
);
2263 purple_signal_emit(purple_conversations_get_handle(),
2264 "conversation-extended-menu", conv
, &menu
);
2268 void purple_conversation_clear_message_history(PurpleConversation
*conv
)
2270 GList
*list
= conv
->message_history
;
2271 message_history_free(list
);
2272 conv
->message_history
= NULL
;
2275 GList
*purple_conversation_get_message_history(PurpleConversation
*conv
)
2277 return conv
->message_history
;
2280 const char *purple_conversation_message_get_sender(PurpleConvMessage
*msg
)
2282 g_return_val_if_fail(msg
, NULL
);
2286 const char *purple_conversation_message_get_message(PurpleConvMessage
*msg
)
2288 g_return_val_if_fail(msg
, NULL
);
2292 PurpleMessageFlags
purple_conversation_message_get_flags(PurpleConvMessage
*msg
)
2294 g_return_val_if_fail(msg
, 0);
2298 time_t purple_conversation_message_get_timestamp(PurpleConvMessage
*msg
)
2300 g_return_val_if_fail(msg
, 0);
2305 purple_conversation_do_command(PurpleConversation
*conv
, const gchar
*cmdline
,
2306 const gchar
*markup
, gchar
**error
)
2308 char *mark
= (markup
&& *markup
) ? NULL
: g_markup_escape_text(cmdline
, -1), *err
= NULL
;
2309 PurpleCmdStatus status
= purple_cmd_do_command(conv
, cmdline
, mark
? mark
: markup
, error
? error
: &err
);
2312 return (status
== PURPLE_CMD_STATUS_OK
);
2316 purple_conversations_get_handle(void)
2324 purple_conversations_init(void)
2326 void *handle
= purple_conversations_get_handle();
2328 conversation_cache
= g_hash_table_new_full((GHashFunc
)_purple_conversations_hconv_hash
,
2329 (GEqualFunc
)_purple_conversations_hconv_equal
,
2330 (GDestroyNotify
)_purple_conversations_hconv_free_key
, NULL
);
2332 /**********************************************************************
2333 * Register preferences
2334 **********************************************************************/
2337 purple_prefs_add_none("/purple/conversations");
2339 /* Conversations -> Chat */
2340 purple_prefs_add_none("/purple/conversations/chat");
2341 purple_prefs_add_bool("/purple/conversations/chat/show_nick_change", TRUE
);
2343 /* Conversations -> IM */
2344 purple_prefs_add_none("/purple/conversations/im");
2345 purple_prefs_add_bool("/purple/conversations/im/send_typing", TRUE
);
2348 /**********************************************************************
2350 **********************************************************************/
2351 purple_signal_register(handle
, "writing-im-msg",
2352 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT
,
2353 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2354 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2355 PURPLE_SUBTYPE_ACCOUNT
),
2356 purple_value_new(PURPLE_TYPE_STRING
),
2357 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2358 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2359 PURPLE_SUBTYPE_CONVERSATION
),
2360 purple_value_new(PURPLE_TYPE_UINT
));
2362 purple_signal_register(handle
, "wrote-im-msg",
2363 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2365 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2366 PURPLE_SUBTYPE_ACCOUNT
),
2367 purple_value_new(PURPLE_TYPE_STRING
),
2368 purple_value_new(PURPLE_TYPE_STRING
),
2369 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2370 PURPLE_SUBTYPE_CONVERSATION
),
2371 purple_value_new(PURPLE_TYPE_UINT
));
2373 purple_signal_register(handle
, "sent-attention",
2374 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT
,
2376 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2377 PURPLE_SUBTYPE_ACCOUNT
),
2378 purple_value_new(PURPLE_TYPE_STRING
),
2379 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2380 PURPLE_SUBTYPE_CONVERSATION
),
2381 purple_value_new(PURPLE_TYPE_UINT
));
2383 purple_signal_register(handle
, "got-attention",
2384 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT
,
2386 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2387 PURPLE_SUBTYPE_ACCOUNT
),
2388 purple_value_new(PURPLE_TYPE_STRING
),
2389 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2390 PURPLE_SUBTYPE_CONVERSATION
),
2391 purple_value_new(PURPLE_TYPE_UINT
));
2393 purple_signal_register(handle
, "sending-im-msg",
2394 purple_marshal_VOID__POINTER_POINTER_POINTER
,
2396 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2397 PURPLE_SUBTYPE_ACCOUNT
),
2398 purple_value_new(PURPLE_TYPE_STRING
),
2399 purple_value_new_outgoing(PURPLE_TYPE_STRING
));
2401 purple_signal_register(handle
, "sent-im-msg",
2402 purple_marshal_VOID__POINTER_POINTER_POINTER
,
2404 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2405 PURPLE_SUBTYPE_ACCOUNT
),
2406 purple_value_new(PURPLE_TYPE_STRING
),
2407 purple_value_new(PURPLE_TYPE_STRING
));
2409 purple_signal_register(handle
, "receiving-im-msg",
2410 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER
,
2411 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2412 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2413 PURPLE_SUBTYPE_ACCOUNT
),
2414 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2415 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2416 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2417 PURPLE_SUBTYPE_CONVERSATION
),
2418 purple_value_new_outgoing(PURPLE_TYPE_UINT
));
2420 purple_signal_register(handle
, "received-im-msg",
2421 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2423 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2424 PURPLE_SUBTYPE_ACCOUNT
),
2425 purple_value_new(PURPLE_TYPE_STRING
),
2426 purple_value_new(PURPLE_TYPE_STRING
),
2427 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2428 PURPLE_SUBTYPE_CONVERSATION
),
2429 purple_value_new(PURPLE_TYPE_UINT
));
2431 purple_signal_register(handle
, "blocked-im-msg",
2432 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT_UINT
,
2434 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2435 PURPLE_SUBTYPE_ACCOUNT
),
2436 purple_value_new(PURPLE_TYPE_STRING
),
2437 purple_value_new(PURPLE_TYPE_STRING
),
2438 purple_value_new(PURPLE_TYPE_UINT
),
2439 purple_value_new(PURPLE_TYPE_UINT
));
2441 purple_signal_register(handle
, "writing-chat-msg",
2442 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT
,
2443 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2444 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2445 PURPLE_SUBTYPE_ACCOUNT
),
2446 purple_value_new(PURPLE_TYPE_STRING
),
2447 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2448 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2449 PURPLE_SUBTYPE_CONVERSATION
),
2450 purple_value_new(PURPLE_TYPE_UINT
));
2452 purple_signal_register(handle
, "wrote-chat-msg",
2453 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2455 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2456 PURPLE_SUBTYPE_ACCOUNT
),
2457 purple_value_new(PURPLE_TYPE_STRING
),
2458 purple_value_new(PURPLE_TYPE_STRING
),
2459 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2460 PURPLE_SUBTYPE_CONVERSATION
),
2461 purple_value_new(PURPLE_TYPE_UINT
));
2463 purple_signal_register(handle
, "sending-chat-msg",
2464 purple_marshal_VOID__POINTER_POINTER_UINT
, NULL
, 3,
2465 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2466 PURPLE_SUBTYPE_ACCOUNT
),
2467 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2468 purple_value_new(PURPLE_TYPE_UINT
));
2470 purple_signal_register(handle
, "sent-chat-msg",
2471 purple_marshal_VOID__POINTER_POINTER_UINT
, NULL
, 3,
2472 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2473 PURPLE_SUBTYPE_ACCOUNT
),
2474 purple_value_new(PURPLE_TYPE_STRING
),
2475 purple_value_new(PURPLE_TYPE_UINT
));
2477 purple_signal_register(handle
, "receiving-chat-msg",
2478 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER
,
2479 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2480 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2481 PURPLE_SUBTYPE_ACCOUNT
),
2482 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2483 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2484 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2485 PURPLE_SUBTYPE_CONVERSATION
),
2486 purple_value_new_outgoing(PURPLE_TYPE_UINT
));
2488 purple_signal_register(handle
, "received-chat-msg",
2489 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2491 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2492 PURPLE_SUBTYPE_ACCOUNT
),
2493 purple_value_new(PURPLE_TYPE_STRING
),
2494 purple_value_new(PURPLE_TYPE_STRING
),
2495 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2496 PURPLE_SUBTYPE_CONVERSATION
),
2497 purple_value_new(PURPLE_TYPE_UINT
));
2499 purple_signal_register(handle
, "conversation-created",
2500 purple_marshal_VOID__POINTER
, NULL
, 1,
2501 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2502 PURPLE_SUBTYPE_CONVERSATION
));
2504 purple_signal_register(handle
, "conversation-updated",
2505 purple_marshal_VOID__POINTER_UINT
, NULL
, 2,
2506 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2507 PURPLE_SUBTYPE_CONVERSATION
),
2508 purple_value_new(PURPLE_TYPE_UINT
));
2510 purple_signal_register(handle
, "deleting-conversation",
2511 purple_marshal_VOID__POINTER
, NULL
, 1,
2512 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2513 PURPLE_SUBTYPE_CONVERSATION
));
2515 purple_signal_register(handle
, "buddy-typing",
2516 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2517 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2518 PURPLE_SUBTYPE_ACCOUNT
),
2519 purple_value_new(PURPLE_TYPE_STRING
));
2521 purple_signal_register(handle
, "buddy-typed",
2522 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2523 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2524 PURPLE_SUBTYPE_ACCOUNT
),
2525 purple_value_new(PURPLE_TYPE_STRING
));
2527 purple_signal_register(handle
, "buddy-typing-stopped",
2528 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2529 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2530 PURPLE_SUBTYPE_ACCOUNT
),
2531 purple_value_new(PURPLE_TYPE_STRING
));
2533 purple_signal_register(handle
, "chat-buddy-joining",
2534 purple_marshal_BOOLEAN__POINTER_POINTER_UINT
,
2535 purple_value_new(PURPLE_TYPE_BOOLEAN
), 3,
2536 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2537 PURPLE_SUBTYPE_CONVERSATION
),
2538 purple_value_new(PURPLE_TYPE_STRING
),
2539 purple_value_new(PURPLE_TYPE_UINT
));
2541 purple_signal_register(handle
, "chat-buddy-joined",
2542 purple_marshal_VOID__POINTER_POINTER_UINT_UINT
, NULL
, 4,
2543 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2544 PURPLE_SUBTYPE_CONVERSATION
),
2545 purple_value_new(PURPLE_TYPE_STRING
),
2546 purple_value_new(PURPLE_TYPE_UINT
),
2547 purple_value_new(PURPLE_TYPE_BOOLEAN
));
2549 purple_signal_register(handle
, "chat-buddy-flags",
2550 purple_marshal_VOID__POINTER_POINTER_UINT_UINT
, NULL
, 4,
2551 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2552 PURPLE_SUBTYPE_CONVERSATION
),
2553 purple_value_new(PURPLE_TYPE_STRING
),
2554 purple_value_new(PURPLE_TYPE_UINT
),
2555 purple_value_new(PURPLE_TYPE_UINT
));
2557 purple_signal_register(handle
, "chat-buddy-leaving",
2558 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
2559 purple_value_new(PURPLE_TYPE_BOOLEAN
), 3,
2560 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2561 PURPLE_SUBTYPE_CONVERSATION
),
2562 purple_value_new(PURPLE_TYPE_STRING
),
2563 purple_value_new(PURPLE_TYPE_STRING
));
2565 purple_signal_register(handle
, "chat-buddy-left",
2566 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2567 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2568 PURPLE_SUBTYPE_CONVERSATION
),
2569 purple_value_new(PURPLE_TYPE_STRING
),
2570 purple_value_new(PURPLE_TYPE_STRING
));
2572 purple_signal_register(handle
, "chat-inviting-user",
2573 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2574 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2575 PURPLE_SUBTYPE_CONVERSATION
),
2576 purple_value_new(PURPLE_TYPE_STRING
),
2577 purple_value_new_outgoing(PURPLE_TYPE_STRING
));
2579 purple_signal_register(handle
, "chat-invited-user",
2580 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2581 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2582 PURPLE_SUBTYPE_CONVERSATION
),
2583 purple_value_new(PURPLE_TYPE_STRING
),
2584 purple_value_new(PURPLE_TYPE_STRING
));
2586 purple_signal_register(handle
, "chat-invited",
2587 purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER
,
2588 purple_value_new(PURPLE_TYPE_INT
), 5,
2589 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2590 PURPLE_SUBTYPE_ACCOUNT
),
2591 purple_value_new(PURPLE_TYPE_STRING
),
2592 purple_value_new(PURPLE_TYPE_STRING
),
2593 purple_value_new(PURPLE_TYPE_STRING
),
2594 purple_value_new(PURPLE_TYPE_POINTER
));
2596 purple_signal_register(handle
, "chat-invite-blocked",
2597 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_POINTER
,
2599 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2600 PURPLE_SUBTYPE_ACCOUNT
),
2601 purple_value_new(PURPLE_TYPE_STRING
),
2602 purple_value_new(PURPLE_TYPE_STRING
),
2603 purple_value_new(PURPLE_TYPE_STRING
),
2604 purple_value_new(PURPLE_TYPE_BOXED
, "GHashTable *"));
2606 purple_signal_register(handle
, "chat-joined",
2607 purple_marshal_VOID__POINTER
, NULL
, 1,
2608 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2609 PURPLE_SUBTYPE_CONVERSATION
));
2611 purple_signal_register(handle
, "chat-join-failed",
2612 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2613 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2614 PURPLE_SUBTYPE_CONNECTION
),
2615 purple_value_new(PURPLE_TYPE_POINTER
));
2617 purple_signal_register(handle
, "chat-left",
2618 purple_marshal_VOID__POINTER
, NULL
, 1,
2619 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2620 PURPLE_SUBTYPE_CONVERSATION
));
2622 purple_signal_register(handle
, "chat-topic-changed",
2623 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2624 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2625 PURPLE_SUBTYPE_CONVERSATION
),
2626 purple_value_new(PURPLE_TYPE_STRING
),
2627 purple_value_new(PURPLE_TYPE_STRING
));
2629 purple_signal_register(handle
, "conversation-extended-menu",
2630 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2631 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2632 PURPLE_SUBTYPE_CONVERSATION
),
2633 purple_value_new(PURPLE_TYPE_BOXED
, "GList **"));
2637 purple_conversations_uninit(void)
2639 while (conversations
)
2640 purple_conversation_destroy((PurpleConversation
*)conversations
->data
);
2641 g_hash_table_destroy(conversation_cache
);
2642 purple_signals_unregister_by_instance(purple_conversations_get_handle());