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
);
578 conv
->ui_data
= NULL
;
580 purple_conversation_close_logs(conv
);
582 purple_conversation_clear_message_history(conv
);
584 PURPLE_DBUS_UNREGISTER_POINTER(conv
);
591 purple_conversation_present(PurpleConversation
*conv
) {
592 PurpleConversationUiOps
*ops
;
594 g_return_if_fail(conv
!= NULL
);
596 ops
= purple_conversation_get_ui_ops(conv
);
597 if(ops
&& ops
->present
)
603 purple_conversation_set_features(PurpleConversation
*conv
, PurpleConnectionFlags features
)
605 g_return_if_fail(conv
!= NULL
);
607 conv
->features
= features
;
609 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_FEATURES
);
613 PurpleConnectionFlags
614 purple_conversation_get_features(PurpleConversation
*conv
)
616 g_return_val_if_fail(conv
!= NULL
, 0);
617 return conv
->features
;
621 PurpleConversationType
622 purple_conversation_get_type(const PurpleConversation
*conv
)
624 g_return_val_if_fail(conv
!= NULL
, PURPLE_CONV_TYPE_UNKNOWN
);
630 purple_conversation_set_ui_ops(PurpleConversation
*conv
,
631 PurpleConversationUiOps
*ops
)
633 g_return_if_fail(conv
!= NULL
);
635 if (conv
->ui_ops
== ops
)
638 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->destroy_conversation
!= NULL
)
639 conv
->ui_ops
->destroy_conversation(conv
);
641 conv
->ui_data
= NULL
;
646 PurpleConversationUiOps
*
647 purple_conversation_get_ui_ops(const PurpleConversation
*conv
)
649 g_return_val_if_fail(conv
!= NULL
, NULL
);
655 purple_conversation_set_account(PurpleConversation
*conv
, PurpleAccount
*account
)
657 g_return_if_fail(conv
!= NULL
);
659 if (account
== purple_conversation_get_account(conv
))
662 conv
->account
= account
;
664 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_ACCOUNT
);
668 purple_conversation_get_account(const PurpleConversation
*conv
)
670 g_return_val_if_fail(conv
!= NULL
, NULL
);
672 return conv
->account
;
676 purple_conversation_get_gc(const PurpleConversation
*conv
)
678 PurpleAccount
*account
;
680 g_return_val_if_fail(conv
!= NULL
, NULL
);
682 account
= purple_conversation_get_account(conv
);
691 purple_conversation_set_title(PurpleConversation
*conv
, const char *title
)
693 g_return_if_fail(conv
!= NULL
);
694 g_return_if_fail(title
!= NULL
);
697 conv
->title
= g_strdup(title
);
699 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_TITLE
);
703 purple_conversation_get_title(const PurpleConversation
*conv
)
705 g_return_val_if_fail(conv
!= NULL
, NULL
);
711 purple_conversation_autoset_title(PurpleConversation
*conv
)
713 PurpleAccount
*account
;
716 const char *text
= NULL
, *name
;
718 g_return_if_fail(conv
!= NULL
);
720 account
= purple_conversation_get_account(conv
);
721 name
= purple_conversation_get_name(conv
);
723 if(purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
) {
724 if(account
&& ((b
= purple_find_buddy(account
, name
)) != NULL
))
725 text
= purple_buddy_get_contact_alias(b
);
726 } else if(purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
) {
727 if(account
&& ((chat
= purple_blist_find_chat(account
, name
)) != NULL
))
728 text
= purple_chat_get_name(chat
);
735 purple_conversation_set_title(conv
, text
);
739 purple_conversation_foreach(void (*func
)(PurpleConversation
*conv
))
741 PurpleConversation
*conv
;
744 g_return_if_fail(func
!= NULL
);
746 for (l
= purple_get_conversations(); l
!= NULL
; l
= l
->next
) {
747 conv
= (PurpleConversation
*)l
->data
;
754 purple_conversation_set_name(PurpleConversation
*conv
, const char *name
)
756 struct _purple_hconv
*hc
;
757 g_return_if_fail(conv
!= NULL
);
759 hc
= g_new(struct _purple_hconv
, 1);
760 hc
->type
= conv
->type
;
761 hc
->account
= conv
->account
;
762 hc
->name
= (gchar
*)purple_normalize(conv
->account
, conv
->name
);
764 g_hash_table_remove(conversation_cache
, hc
);
767 conv
->name
= g_strdup(name
);
768 hc
->name
= g_strdup(purple_normalize(conv
->account
, conv
->name
));
769 g_hash_table_insert(conversation_cache
, hc
, conv
);
771 purple_conversation_autoset_title(conv
);
775 purple_conversation_get_name(const PurpleConversation
*conv
)
777 g_return_val_if_fail(conv
!= NULL
, NULL
);
783 purple_conversation_set_logging(PurpleConversation
*conv
, gboolean log
)
785 g_return_if_fail(conv
!= NULL
);
787 if (conv
->logging
!= log
)
790 purple_conversation_update(conv
, PURPLE_CONV_UPDATE_LOGGING
);
795 purple_conversation_is_logging(const PurpleConversation
*conv
)
797 g_return_val_if_fail(conv
!= NULL
, FALSE
);
799 return conv
->logging
;
803 purple_conversation_close_logs(PurpleConversation
*conv
)
805 g_return_if_fail(conv
!= NULL
);
807 g_list_foreach(conv
->logs
, (GFunc
)purple_log_free
, NULL
);
808 g_list_free(conv
->logs
);
813 purple_conversation_get_im_data(const PurpleConversation
*conv
)
815 g_return_val_if_fail(conv
!= NULL
, NULL
);
817 if (purple_conversation_get_type(conv
) != PURPLE_CONV_TYPE_IM
)
824 purple_conversation_get_chat_data(const PurpleConversation
*conv
)
826 g_return_val_if_fail(conv
!= NULL
, NULL
);
828 if (purple_conversation_get_type(conv
) != PURPLE_CONV_TYPE_CHAT
)
835 purple_conversation_set_data(PurpleConversation
*conv
, const char *key
,
838 g_return_if_fail(conv
!= NULL
);
839 g_return_if_fail(key
!= NULL
);
841 g_hash_table_replace(conv
->data
, g_strdup(key
), data
);
845 purple_conversation_get_data(PurpleConversation
*conv
, const char *key
)
847 g_return_val_if_fail(conv
!= NULL
, NULL
);
848 g_return_val_if_fail(key
!= NULL
, NULL
);
850 return g_hash_table_lookup(conv
->data
, key
);
854 purple_get_conversations(void)
856 return conversations
;
866 purple_get_chats(void)
873 purple_find_conversation_with_account(PurpleConversationType type
,
875 const PurpleAccount
*account
)
877 PurpleConversation
*c
= NULL
;
878 struct _purple_hconv hc
;
880 g_return_val_if_fail(name
!= NULL
, NULL
);
882 hc
.name
= (gchar
*)purple_normalize(account
, name
);
883 hc
.account
= account
;
887 case PURPLE_CONV_TYPE_IM
:
888 case PURPLE_CONV_TYPE_CHAT
:
889 c
= g_hash_table_lookup(conversation_cache
, &hc
);
891 case PURPLE_CONV_TYPE_ANY
:
892 hc
.type
= PURPLE_CONV_TYPE_IM
;
893 c
= g_hash_table_lookup(conversation_cache
, &hc
);
895 hc
.type
= PURPLE_CONV_TYPE_CHAT
;
896 c
= g_hash_table_lookup(conversation_cache
, &hc
);
900 g_return_val_if_reached(NULL
);
907 purple_conversation_write(PurpleConversation
*conv
, const char *who
,
908 const char *message
, PurpleMessageFlags flags
,
911 PurplePluginProtocolInfo
*prpl_info
= NULL
;
912 PurpleConnection
*gc
= NULL
;
913 PurpleAccount
*account
;
914 PurpleConversationUiOps
*ops
;
916 char *displayed
= NULL
;
919 PurpleConversationType type
;
920 /* int logging_font_options = 0; */
922 g_return_if_fail(conv
!= NULL
);
923 g_return_if_fail(message
!= NULL
);
925 ops
= purple_conversation_get_ui_ops(conv
);
927 account
= purple_conversation_get_account(conv
);
928 type
= purple_conversation_get_type(conv
);
931 gc
= purple_account_get_connection(account
);
933 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
&&
934 (gc
!= NULL
&& !g_slist_find(gc
->buddy_chats
, conv
)))
937 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
&&
938 !g_list_find(purple_get_conversations(), conv
))
941 displayed
= g_strdup(message
);
943 if (who
== NULL
|| *who
== '\0')
944 who
= purple_conversation_get_name(conv
);
948 GPOINTER_TO_INT(purple_signal_emit_return_1(
949 purple_conversations_get_handle(),
950 (type
== PURPLE_CONV_TYPE_IM
? "writing-im-msg" : "writing-chat-msg"),
951 account
, who
, &displayed
, conv
, flags
));
953 if (displayed
== NULL
)
961 if (account
!= NULL
) {
962 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_find_prpl(purple_account_get_protocol_id(account
)));
964 if (purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
||
965 !(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
967 if (flags
& PURPLE_MESSAGE_SEND
) {
968 b
= purple_find_buddy(account
,
969 purple_account_get_username(account
));
971 if (purple_account_get_alias(account
) != NULL
)
972 alias
= account
->alias
;
973 else if (b
!= NULL
&& !purple_strequal(purple_buddy_get_name(b
), purple_buddy_get_contact_alias(b
)))
974 alias
= purple_buddy_get_contact_alias(b
);
975 else if (purple_connection_get_display_name(gc
) != NULL
)
976 alias
= purple_connection_get_display_name(gc
);
978 alias
= purple_account_get_username(account
);
982 b
= purple_find_buddy(account
, who
);
985 alias
= purple_buddy_get_contact_alias(b
);
990 if (!(flags
& PURPLE_MESSAGE_NO_LOG
) && purple_conversation_is_logging(conv
)) {
993 if (conv
->logs
== NULL
)
997 while (log
!= NULL
) {
998 purple_log_write((PurpleLog
*)log
->data
, flags
, alias
, mtime
, displayed
);
1003 if (ops
&& ops
->write_conv
)
1004 ops
->write_conv(conv
, who
, alias
, displayed
, flags
, mtime
);
1006 add_message_to_history(conv
, who
, alias
, message
, flags
, mtime
);
1008 purple_signal_emit(purple_conversations_get_handle(),
1009 (type
== PURPLE_CONV_TYPE_IM
? "wrote-im-msg" : "wrote-chat-msg"),
1010 account
, who
, displayed
, conv
, flags
);
1016 purple_conversation_has_focus(PurpleConversation
*conv
)
1018 gboolean ret
= FALSE
;
1019 PurpleConversationUiOps
*ops
;
1021 g_return_val_if_fail(conv
!= NULL
, FALSE
);
1023 ops
= purple_conversation_get_ui_ops(conv
);
1025 if (ops
!= NULL
&& ops
->has_focus
!= NULL
)
1026 ret
= ops
->has_focus(conv
);
1032 * TODO: Need to make sure calls to this function happen in the core
1033 * instead of the UI. That way UIs have less work to do, and the
1034 * core/UI split is cleaner. Also need to make sure this is called
1035 * when chats are added/removed from the blist.
1038 purple_conversation_update(PurpleConversation
*conv
, PurpleConvUpdateType type
)
1040 g_return_if_fail(conv
!= NULL
);
1042 purple_signal_emit(purple_conversations_get_handle(),
1043 "conversation-updated", conv
, type
);
1046 /**************************************************************************
1047 * IM Conversation API
1048 **************************************************************************/
1049 PurpleConversation
*
1050 purple_conv_im_get_conversation(const PurpleConvIm
*im
)
1052 g_return_val_if_fail(im
!= NULL
, NULL
);
1058 purple_conv_im_set_icon(PurpleConvIm
*im
, PurpleBuddyIcon
*icon
)
1060 g_return_if_fail(im
!= NULL
);
1062 if (im
->icon
!= icon
)
1064 purple_buddy_icon_unref(im
->icon
);
1066 im
->icon
= (icon
== NULL
? NULL
: purple_buddy_icon_ref(icon
));
1069 purple_conversation_update(purple_conv_im_get_conversation(im
),
1070 PURPLE_CONV_UPDATE_ICON
);
1074 purple_conv_im_get_icon(const PurpleConvIm
*im
)
1076 g_return_val_if_fail(im
!= NULL
, NULL
);
1082 purple_conv_im_set_typing_state(PurpleConvIm
*im
, PurpleTypingState state
)
1084 g_return_if_fail(im
!= NULL
);
1086 if (im
->typing_state
!= state
)
1088 im
->typing_state
= state
;
1093 purple_signal_emit(purple_conversations_get_handle(),
1094 "buddy-typing", im
->conv
->account
, im
->conv
->name
);
1097 purple_signal_emit(purple_conversations_get_handle(),
1098 "buddy-typed", im
->conv
->account
, im
->conv
->name
);
1100 case PURPLE_NOT_TYPING
:
1101 purple_signal_emit(purple_conversations_get_handle(),
1102 "buddy-typing-stopped", im
->conv
->account
, im
->conv
->name
);
1106 purple_conv_im_update_typing(im
);
1111 purple_conv_im_get_typing_state(const PurpleConvIm
*im
)
1113 g_return_val_if_fail(im
!= NULL
, 0);
1115 return im
->typing_state
;
1119 purple_conv_im_start_typing_timeout(PurpleConvIm
*im
, int timeout
)
1121 PurpleConversation
*conv
;
1123 g_return_if_fail(im
!= NULL
);
1125 if (im
->typing_timeout
> 0)
1126 purple_conv_im_stop_typing_timeout(im
);
1128 conv
= purple_conv_im_get_conversation(im
);
1130 im
->typing_timeout
= purple_timeout_add_seconds(timeout
, reset_typing_cb
, conv
);
1134 purple_conv_im_stop_typing_timeout(PurpleConvIm
*im
)
1136 g_return_if_fail(im
!= NULL
);
1138 if (im
->typing_timeout
== 0)
1141 purple_timeout_remove(im
->typing_timeout
);
1142 im
->typing_timeout
= 0;
1146 purple_conv_im_get_typing_timeout(const PurpleConvIm
*im
)
1148 g_return_val_if_fail(im
!= NULL
, 0);
1150 return im
->typing_timeout
;
1154 purple_conv_im_set_type_again(PurpleConvIm
*im
, unsigned int val
)
1156 g_return_if_fail(im
!= NULL
);
1161 im
->type_again
= time(NULL
) + val
;
1165 purple_conv_im_get_type_again(const PurpleConvIm
*im
)
1167 g_return_val_if_fail(im
!= NULL
, 0);
1169 return im
->type_again
;
1173 purple_conv_im_start_send_typed_timeout(PurpleConvIm
*im
)
1175 g_return_if_fail(im
!= NULL
);
1177 im
->send_typed_timeout
= purple_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS
,
1179 purple_conv_im_get_conversation(im
));
1183 purple_conv_im_stop_send_typed_timeout(PurpleConvIm
*im
)
1185 g_return_if_fail(im
!= NULL
);
1187 if (im
->send_typed_timeout
== 0)
1190 purple_timeout_remove(im
->send_typed_timeout
);
1191 im
->send_typed_timeout
= 0;
1195 purple_conv_im_get_send_typed_timeout(const PurpleConvIm
*im
)
1197 g_return_val_if_fail(im
!= NULL
, 0);
1199 return im
->send_typed_timeout
;
1203 purple_conv_im_update_typing(PurpleConvIm
*im
)
1205 g_return_if_fail(im
!= NULL
);
1207 purple_conversation_update(purple_conv_im_get_conversation(im
),
1208 PURPLE_CONV_UPDATE_TYPING
);
1212 purple_conv_im_write(PurpleConvIm
*im
, const char *who
, const char *message
,
1213 PurpleMessageFlags flags
, time_t mtime
)
1215 PurpleConversation
*c
;
1217 g_return_if_fail(im
!= NULL
);
1218 g_return_if_fail(message
!= NULL
);
1220 c
= purple_conv_im_get_conversation(im
);
1222 if ((flags
& PURPLE_MESSAGE_RECV
) == PURPLE_MESSAGE_RECV
) {
1223 purple_conv_im_set_typing_state(im
, PURPLE_NOT_TYPING
);
1226 /* Pass this on to either the ops structure or the default write func. */
1227 if (c
->ui_ops
!= NULL
&& c
->ui_ops
->write_im
!= NULL
)
1228 c
->ui_ops
->write_im(c
, who
, message
, flags
, mtime
);
1230 purple_conversation_write(c
, who
, message
, flags
, mtime
);
1233 gboolean
purple_conv_present_error(const char *who
, PurpleAccount
*account
, const char *what
)
1235 PurpleConversation
*conv
;
1237 g_return_val_if_fail(who
!= NULL
, FALSE
);
1238 g_return_val_if_fail(account
!=NULL
, FALSE
);
1239 g_return_val_if_fail(what
!= NULL
, FALSE
);
1241 conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_ANY
, who
, account
);
1243 purple_conversation_write(conv
, NULL
, what
, PURPLE_MESSAGE_ERROR
, time(NULL
));
1251 purple_conv_im_send(PurpleConvIm
*im
, const char *message
)
1253 purple_conv_im_send_with_flags(im
, message
, 0);
1257 purple_conv_send_confirm_cb(gpointer
*data
)
1259 PurpleConversation
*conv
= data
[0];
1260 char *message
= data
[1];
1263 common_send(conv
, message
, 0);
1267 purple_conv_send_confirm(PurpleConversation
*conv
, const char *message
)
1272 g_return_if_fail(conv
!= NULL
);
1273 g_return_if_fail(message
!= NULL
);
1275 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->send_confirm
!= NULL
)
1277 conv
->ui_ops
->send_confirm(conv
, message
);
1281 text
= g_strdup_printf("You are about to send the following message:\n%s", message
);
1282 data
= g_new0(gpointer
, 2);
1284 data
[1] = (gpointer
)message
;
1286 purple_request_action(conv
, NULL
, _("Send Message"), text
, 0,
1287 purple_conversation_get_account(conv
), NULL
, conv
,
1289 _("_Send Message"), G_CALLBACK(purple_conv_send_confirm_cb
),
1294 purple_conv_im_send_with_flags(PurpleConvIm
*im
, const char *message
, PurpleMessageFlags flags
)
1296 g_return_if_fail(im
!= NULL
);
1297 g_return_if_fail(message
!= NULL
);
1299 common_send(purple_conv_im_get_conversation(im
), message
, flags
);
1303 purple_conv_custom_smiley_add(PurpleConversation
*conv
, const char *smile
,
1304 const char *cksum_type
, const char *chksum
,
1307 if (conv
== NULL
|| smile
== NULL
|| !*smile
) {
1311 /* TODO: check if the icon is in the cache and return false if so */
1312 /* TODO: add an icon cache (that doesn't suck) */
1313 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->custom_smiley_add
!=NULL
) {
1314 return conv
->ui_ops
->custom_smiley_add(conv
, smile
, remote
);
1316 purple_debug_info("conversation", "Could not find add custom smiley function");
1323 purple_conv_custom_smiley_write(PurpleConversation
*conv
, const char *smile
,
1324 const guchar
*data
, gsize size
)
1326 g_return_if_fail(conv
!= NULL
);
1327 g_return_if_fail(smile
!= NULL
&& *smile
);
1329 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->custom_smiley_write
!= NULL
)
1330 conv
->ui_ops
->custom_smiley_write(conv
, smile
, data
, size
);
1332 purple_debug_info("conversation", "Could not find the smiley write function");
1336 purple_conv_custom_smiley_close(PurpleConversation
*conv
, const char *smile
)
1338 g_return_if_fail(conv
!= NULL
);
1339 g_return_if_fail(smile
!= NULL
&& *smile
);
1341 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->custom_smiley_close
!= NULL
)
1342 conv
->ui_ops
->custom_smiley_close(conv
, smile
);
1344 purple_debug_info("conversation", "Could not find custom smiley close function");
1348 /**************************************************************************
1349 * Chat Conversation API
1350 **************************************************************************/
1352 PurpleConversation
*
1353 purple_conv_chat_get_conversation(const PurpleConvChat
*chat
)
1355 g_return_val_if_fail(chat
!= NULL
, NULL
);
1361 purple_conv_chat_set_users(PurpleConvChat
*chat
, GList
*users
)
1363 g_return_val_if_fail(chat
!= NULL
, NULL
);
1365 chat
->in_room
= users
;
1371 purple_conv_chat_get_users(const PurpleConvChat
*chat
)
1373 g_return_val_if_fail(chat
!= NULL
, NULL
);
1375 return chat
->in_room
;
1379 purple_conv_chat_ignore(PurpleConvChat
*chat
, const char *name
)
1381 g_return_if_fail(chat
!= NULL
);
1382 g_return_if_fail(name
!= NULL
);
1384 /* Make sure the user isn't already ignored. */
1385 if (purple_conv_chat_is_user_ignored(chat
, name
))
1388 purple_conv_chat_set_ignored(chat
,
1389 g_list_append(chat
->ignored
, g_strdup(name
)));
1393 purple_conv_chat_unignore(PurpleConvChat
*chat
, const char *name
)
1397 g_return_if_fail(chat
!= NULL
);
1398 g_return_if_fail(name
!= NULL
);
1400 /* Make sure the user is actually ignored. */
1401 if (!purple_conv_chat_is_user_ignored(chat
, name
))
1404 item
= g_list_find(purple_conv_chat_get_ignored(chat
),
1405 purple_conv_chat_get_ignored_user(chat
, name
));
1407 purple_conv_chat_set_ignored(chat
,
1408 g_list_remove_link(chat
->ignored
, item
));
1411 g_list_free_1(item
);
1415 purple_conv_chat_set_ignored(PurpleConvChat
*chat
, GList
*ignored
)
1417 g_return_val_if_fail(chat
!= NULL
, NULL
);
1419 chat
->ignored
= ignored
;
1425 purple_conv_chat_get_ignored(const PurpleConvChat
*chat
)
1427 g_return_val_if_fail(chat
!= NULL
, NULL
);
1429 return chat
->ignored
;
1433 purple_conv_chat_get_ignored_user(const PurpleConvChat
*chat
, const char *user
)
1437 g_return_val_if_fail(chat
!= NULL
, NULL
);
1438 g_return_val_if_fail(user
!= NULL
, NULL
);
1440 for (ignored
= purple_conv_chat_get_ignored(chat
);
1442 ignored
= ignored
->next
) {
1444 const char *ign
= (const char *)ignored
->data
;
1446 if (!purple_utf8_strcasecmp(user
, ign
) ||
1447 ((*ign
== '+' || *ign
== '%') && !purple_utf8_strcasecmp(user
, ign
+ 1)))
1453 if ((*ign
== '+' && !purple_utf8_strcasecmp(user
, ign
+ 1)) ||
1454 (*ign
!= '+' && !purple_utf8_strcasecmp(user
, ign
)))
1463 purple_conv_chat_is_user_ignored(const PurpleConvChat
*chat
, const char *user
)
1465 g_return_val_if_fail(chat
!= NULL
, FALSE
);
1466 g_return_val_if_fail(user
!= NULL
, FALSE
);
1468 return (purple_conv_chat_get_ignored_user(chat
, user
) != NULL
);
1472 purple_conv_chat_set_topic(PurpleConvChat
*chat
, const char *who
, const char *topic
)
1474 g_return_if_fail(chat
!= NULL
);
1477 g_free(chat
->topic
);
1479 chat
->who
= g_strdup(who
);
1480 chat
->topic
= g_strdup(topic
);
1482 purple_conversation_update(purple_conv_chat_get_conversation(chat
),
1483 PURPLE_CONV_UPDATE_TOPIC
);
1485 purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed",
1486 chat
->conv
, chat
->who
, chat
->topic
);
1490 purple_conv_chat_get_topic(const PurpleConvChat
*chat
)
1492 g_return_val_if_fail(chat
!= NULL
, NULL
);
1498 purple_conv_chat_set_id(PurpleConvChat
*chat
, int id
)
1500 g_return_if_fail(chat
!= NULL
);
1506 purple_conv_chat_get_id(const PurpleConvChat
*chat
)
1508 g_return_val_if_fail(chat
!= NULL
, -1);
1514 purple_conv_chat_write(PurpleConvChat
*chat
, const char *who
, const char *message
,
1515 PurpleMessageFlags flags
, time_t mtime
)
1517 PurpleAccount
*account
;
1518 PurpleConversation
*conv
;
1519 PurpleConnection
*gc
;
1521 g_return_if_fail(chat
!= NULL
);
1522 g_return_if_fail(who
!= NULL
);
1523 g_return_if_fail(message
!= NULL
);
1525 conv
= purple_conv_chat_get_conversation(chat
);
1526 gc
= purple_conversation_get_gc(conv
);
1527 account
= purple_connection_get_account(gc
);
1529 /* Don't display this if the person who wrote it is ignored. */
1530 if (purple_conv_chat_is_user_ignored(chat
, who
))
1533 if (!(flags
& PURPLE_MESSAGE_WHISPER
)) {
1536 str
= purple_normalize(account
, who
);
1538 if (purple_strequal(str
, chat
->nick
)) {
1539 flags
|= PURPLE_MESSAGE_SEND
;
1541 flags
|= PURPLE_MESSAGE_RECV
;
1543 if (purple_utf8_has_word(message
, chat
->nick
))
1544 flags
|= PURPLE_MESSAGE_NICK
;
1548 /* Pass this on to either the ops structure or the default write func. */
1549 if (conv
->ui_ops
!= NULL
&& conv
->ui_ops
->write_chat
!= NULL
)
1550 conv
->ui_ops
->write_chat(conv
, who
, message
, flags
, mtime
);
1552 purple_conversation_write(conv
, who
, message
, flags
, mtime
);
1556 purple_conv_chat_send(PurpleConvChat
*chat
, const char *message
)
1558 purple_conv_chat_send_with_flags(chat
, message
, 0);
1562 purple_conv_chat_send_with_flags(PurpleConvChat
*chat
, const char *message
, PurpleMessageFlags flags
)
1564 g_return_if_fail(chat
!= NULL
);
1565 g_return_if_fail(message
!= NULL
);
1567 common_send(purple_conv_chat_get_conversation(chat
), message
, flags
);
1571 purple_conv_chat_add_user(PurpleConvChat
*chat
, const char *user
,
1572 const char *extra_msg
, PurpleConvChatBuddyFlags flags
,
1573 gboolean new_arrival
)
1575 GList
*users
= g_list_append(NULL
, (char *)user
);
1576 GList
*extra_msgs
= g_list_append(NULL
, (char *)extra_msg
);
1577 GList
*flags2
= g_list_append(NULL
, GINT_TO_POINTER(flags
));
1579 purple_conv_chat_add_users(chat
, users
, extra_msgs
, flags2
, new_arrival
);
1582 g_list_free(extra_msgs
);
1583 g_list_free(flags2
);
1587 purple_conv_chat_cb_compare(PurpleConvChatBuddy
*a
, PurpleConvChatBuddy
*b
)
1589 PurpleConvChatBuddyFlags f1
= 0, f2
= 0;
1590 char *user1
= NULL
, *user2
= NULL
;
1596 user1
= a
->alias_key
;
1604 user2
= b
->alias_key
;
1609 if (user1
== NULL
|| user2
== NULL
) {
1610 if (!(user1
== NULL
&& user2
== NULL
))
1611 ret
= (user1
== NULL
) ? -1: 1;
1612 } else if (f1
!= f2
) {
1613 /* sort more important users first */
1614 ret
= (f1
> f2
) ? -1 : 1;
1615 } else if (a
->buddy
!= b
->buddy
) {
1616 ret
= a
->buddy
? -1 : 1;
1618 ret
= purple_utf8_strcasecmp(user1
, user2
);
1625 purple_conv_chat_add_users(PurpleConvChat
*chat
, GList
*users
, GList
*extra_msgs
,
1626 GList
*flags
, gboolean new_arrivals
)
1628 PurpleConversation
*conv
;
1629 PurpleConversationUiOps
*ops
;
1630 PurpleConvChatBuddy
*cbuddy
;
1631 PurpleConnection
*gc
;
1632 PurplePluginProtocolInfo
*prpl_info
;
1634 GList
*cbuddies
= NULL
;
1636 g_return_if_fail(chat
!= NULL
);
1637 g_return_if_fail(users
!= NULL
);
1639 conv
= purple_conv_chat_get_conversation(chat
);
1640 ops
= purple_conversation_get_ui_ops(conv
);
1642 gc
= purple_conversation_get_gc(conv
);
1643 g_return_if_fail(gc
!= NULL
);
1644 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1645 g_return_if_fail(prpl_info
!= NULL
);
1649 while ((ul
!= NULL
) && (fl
!= NULL
)) {
1650 const char *user
= (const char *)ul
->data
;
1651 const char *alias
= user
;
1653 PurpleConvChatBuddyFlags flag
= GPOINTER_TO_INT(fl
->data
);
1654 const char *extra_msg
= (extra_msgs
? extra_msgs
->data
: NULL
);
1656 if(!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1657 if (purple_strequal(chat
->nick
, purple_normalize(conv
->account
, user
))) {
1658 const char *alias2
= purple_account_get_alias(conv
->account
);
1663 const char *display_name
= purple_connection_get_display_name(gc
);
1664 if (display_name
!= NULL
)
1665 alias
= display_name
;
1669 if ((buddy
= purple_find_buddy(gc
->account
, user
)) != NULL
)
1670 alias
= purple_buddy_get_contact_alias(buddy
);
1674 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
1675 "chat-buddy-joining", conv
, user
, flag
)) ||
1676 purple_conv_chat_is_user_ignored(chat
, user
);
1678 cbuddy
= purple_conv_chat_cb_new(user
, alias
, flag
);
1679 cbuddy
->buddy
= purple_find_buddy(conv
->account
, user
) != NULL
;
1680 /* This seems dumb. Why should we set users thousands of times? */
1681 purple_conv_chat_set_users(chat
,
1682 g_list_prepend(chat
->in_room
, cbuddy
));
1684 cbuddies
= g_list_prepend(cbuddies
, cbuddy
);
1686 if (!quiet
&& new_arrivals
) {
1687 char *alias_esc
= g_markup_escape_text(alias
, -1);
1690 if (extra_msg
== NULL
)
1691 tmp
= g_strdup_printf(_("%s entered the room."), alias_esc
);
1693 char *extra_msg_esc
= g_markup_escape_text(extra_msg
, -1);
1694 tmp
= g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
1695 alias_esc
, extra_msg_esc
);
1696 g_free(extra_msg_esc
);
1700 purple_conversation_write(conv
, NULL
, tmp
,
1701 PURPLE_MESSAGE_SYSTEM
| PURPLE_MESSAGE_NO_LINKIFY
,
1706 purple_signal_emit(purple_conversations_get_handle(),
1707 "chat-buddy-joined", conv
, user
, flag
, new_arrivals
);
1710 if (extra_msgs
!= NULL
)
1711 extra_msgs
= extra_msgs
->next
;
1714 cbuddies
= g_list_sort(cbuddies
, (GCompareFunc
)purple_conv_chat_cb_compare
);
1716 if (ops
!= NULL
&& ops
->chat_add_users
!= NULL
)
1717 ops
->chat_add_users(conv
, cbuddies
, new_arrivals
);
1719 g_list_free(cbuddies
);
1723 purple_conv_chat_rename_user(PurpleConvChat
*chat
, const char *old_user
,
1724 const char *new_user
)
1726 PurpleConversation
*conv
;
1727 PurpleConversationUiOps
*ops
;
1728 PurpleConnection
*gc
;
1729 PurplePluginProtocolInfo
*prpl_info
;
1730 PurpleConvChatBuddy
*cb
;
1731 PurpleConvChatBuddyFlags flags
;
1732 const char *new_alias
= new_user
;
1734 gboolean is_me
= FALSE
;
1736 g_return_if_fail(chat
!= NULL
);
1737 g_return_if_fail(old_user
!= NULL
);
1738 g_return_if_fail(new_user
!= NULL
);
1740 conv
= purple_conv_chat_get_conversation(chat
);
1741 ops
= purple_conversation_get_ui_ops(conv
);
1743 gc
= purple_conversation_get_gc(conv
);
1744 g_return_if_fail(gc
!= NULL
);
1745 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1746 g_return_if_fail(prpl_info
!= NULL
);
1748 if (purple_strequal(chat
->nick
, purple_normalize(conv
->account
, old_user
))) {
1751 /* Note this for later. */
1754 if(!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1755 alias
= purple_account_get_alias(conv
->account
);
1760 const char *display_name
= purple_connection_get_display_name(gc
);
1761 if (display_name
!= NULL
)
1762 alias
= display_name
;
1765 } else if (!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1767 if ((buddy
= purple_find_buddy(gc
->account
, new_user
)) != NULL
)
1768 new_alias
= purple_buddy_get_contact_alias(buddy
);
1771 flags
= purple_conv_chat_user_get_flags(chat
, old_user
);
1772 cb
= purple_conv_chat_cb_new(new_user
, new_alias
, flags
);
1773 cb
->buddy
= purple_find_buddy(conv
->account
, new_user
) != NULL
;
1774 purple_conv_chat_set_users(chat
,
1775 g_list_prepend(chat
->in_room
, cb
));
1777 if (ops
!= NULL
&& ops
->chat_rename_user
!= NULL
)
1778 ops
->chat_rename_user(conv
, old_user
, new_user
, new_alias
);
1780 cb
= purple_conv_chat_cb_find(chat
, old_user
);
1783 purple_conv_chat_set_users(chat
,
1784 g_list_remove(chat
->in_room
, cb
));
1785 purple_conv_chat_cb_destroy(cb
);
1788 if (purple_conv_chat_is_user_ignored(chat
, old_user
)) {
1789 purple_conv_chat_unignore(chat
, old_user
);
1790 purple_conv_chat_ignore(chat
, new_user
);
1792 else if (purple_conv_chat_is_user_ignored(chat
, new_user
))
1793 purple_conv_chat_unignore(chat
, new_user
);
1796 purple_conv_chat_set_nick(chat
, new_user
);
1798 if (purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") &&
1799 !purple_conv_chat_is_user_ignored(chat
, new_user
)) {
1802 char *escaped
= g_markup_escape_text(new_user
, -1);
1803 g_snprintf(tmp
, sizeof(tmp
),
1804 _("You are now known as %s"), escaped
);
1807 const char *old_alias
= old_user
;
1808 const char *new_alias
= new_user
;
1812 if (!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1815 if ((buddy
= purple_find_buddy(gc
->account
, old_user
)) != NULL
)
1816 old_alias
= purple_buddy_get_contact_alias(buddy
);
1817 if ((buddy
= purple_find_buddy(gc
->account
, new_user
)) != NULL
)
1818 new_alias
= purple_buddy_get_contact_alias(buddy
);
1821 escaped
= g_markup_escape_text(old_alias
, -1);
1822 escaped2
= g_markup_escape_text(new_alias
, -1);
1823 g_snprintf(tmp
, sizeof(tmp
),
1824 _("%s is now known as %s"), escaped
, escaped2
);
1829 purple_conversation_write(conv
, NULL
, tmp
,
1830 PURPLE_MESSAGE_SYSTEM
| PURPLE_MESSAGE_NO_LINKIFY
,
1836 purple_conv_chat_remove_user(PurpleConvChat
*chat
, const char *user
, const char *reason
)
1838 GList
*users
= g_list_append(NULL
, (char *)user
);
1840 purple_conv_chat_remove_users(chat
, users
, reason
);
1846 purple_conv_chat_remove_users(PurpleConvChat
*chat
, GList
*users
, const char *reason
)
1848 PurpleConversation
*conv
;
1849 PurpleConnection
*gc
;
1850 PurplePluginProtocolInfo
*prpl_info
;
1851 PurpleConversationUiOps
*ops
;
1852 PurpleConvChatBuddy
*cb
;
1856 g_return_if_fail(chat
!= NULL
);
1857 g_return_if_fail(users
!= NULL
);
1859 conv
= purple_conv_chat_get_conversation(chat
);
1861 gc
= purple_conversation_get_gc(conv
);
1862 g_return_if_fail(gc
!= NULL
);
1863 prpl_info
= PURPLE_PLUGIN_PROTOCOL_INFO(purple_connection_get_prpl(gc
));
1864 g_return_if_fail(prpl_info
!= NULL
);
1866 ops
= purple_conversation_get_ui_ops(conv
);
1868 for (l
= users
; l
!= NULL
; l
= l
->next
) {
1869 const char *user
= (const char *)l
->data
;
1870 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
1871 "chat-buddy-leaving", conv
, user
, reason
)) |
1872 purple_conv_chat_is_user_ignored(chat
, user
);
1874 cb
= purple_conv_chat_cb_find(chat
, user
);
1877 purple_conv_chat_set_users(chat
,
1878 g_list_remove(chat
->in_room
, cb
));
1879 purple_conv_chat_cb_destroy(cb
);
1882 /* NOTE: Don't remove them from ignored in case they re-enter. */
1885 const char *alias
= user
;
1889 if (!(prpl_info
->options
& OPT_PROTO_UNIQUE_CHATNAME
)) {
1892 if ((buddy
= purple_find_buddy(gc
->account
, user
)) != NULL
)
1893 alias
= purple_buddy_get_contact_alias(buddy
);
1896 alias_esc
= g_markup_escape_text(alias
, -1);
1898 if (reason
== NULL
|| !*reason
)
1899 tmp
= g_strdup_printf(_("%s left the room."), alias_esc
);
1901 char *reason_esc
= g_markup_escape_text(reason
, -1);
1902 tmp
= g_strdup_printf(_("%s left the room (%s)."),
1903 alias_esc
, reason_esc
);
1908 purple_conversation_write(conv
, NULL
, tmp
,
1909 PURPLE_MESSAGE_SYSTEM
| PURPLE_MESSAGE_NO_LINKIFY
,
1914 purple_signal_emit(purple_conversations_get_handle(), "chat-buddy-left",
1915 conv
, user
, reason
);
1918 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
)
1919 ops
->chat_remove_users(conv
, users
);
1923 purple_conv_chat_clear_users(PurpleConvChat
*chat
)
1925 PurpleConversation
*conv
;
1926 PurpleConversationUiOps
*ops
;
1929 GList
*names
= NULL
;
1931 g_return_if_fail(chat
!= NULL
);
1933 conv
= purple_conv_chat_get_conversation(chat
);
1934 ops
= purple_conversation_get_ui_ops(conv
);
1935 users
= chat
->in_room
;
1937 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
) {
1938 for (l
= users
; l
; l
= l
->next
) {
1939 PurpleConvChatBuddy
*cb
= l
->data
;
1940 names
= g_list_prepend(names
, cb
->name
);
1942 ops
->chat_remove_users(conv
, names
);
1946 for (l
= users
; l
; l
= l
->next
)
1948 PurpleConvChatBuddy
*cb
= l
->data
;
1950 purple_signal_emit(purple_conversations_get_handle(),
1951 "chat-buddy-leaving", conv
, cb
->name
, NULL
);
1952 purple_signal_emit(purple_conversations_get_handle(),
1953 "chat-buddy-left", conv
, cb
->name
, NULL
);
1955 purple_conv_chat_cb_destroy(cb
);
1959 purple_conv_chat_set_users(chat
, NULL
);
1964 purple_conv_chat_find_user(PurpleConvChat
*chat
, const char *user
)
1966 g_return_val_if_fail(chat
!= NULL
, FALSE
);
1967 g_return_val_if_fail(user
!= NULL
, FALSE
);
1969 return (purple_conv_chat_cb_find(chat
, user
) != NULL
);
1973 purple_conv_chat_user_set_flags(PurpleConvChat
*chat
, const char *user
,
1974 PurpleConvChatBuddyFlags flags
)
1976 PurpleConversation
*conv
;
1977 PurpleConversationUiOps
*ops
;
1978 PurpleConvChatBuddy
*cb
;
1979 PurpleConvChatBuddyFlags oldflags
;
1981 g_return_if_fail(chat
!= NULL
);
1982 g_return_if_fail(user
!= NULL
);
1984 cb
= purple_conv_chat_cb_find(chat
, user
);
1989 if (flags
== cb
->flags
)
1992 oldflags
= cb
->flags
;
1995 conv
= purple_conv_chat_get_conversation(chat
);
1996 ops
= purple_conversation_get_ui_ops(conv
);
1998 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
1999 ops
->chat_update_user(conv
, user
);
2001 purple_signal_emit(purple_conversations_get_handle(),
2002 "chat-buddy-flags", conv
, user
, oldflags
, flags
);
2005 PurpleConvChatBuddyFlags
2006 purple_conv_chat_user_get_flags(PurpleConvChat
*chat
, const char *user
)
2008 PurpleConvChatBuddy
*cb
;
2010 g_return_val_if_fail(chat
!= NULL
, 0);
2011 g_return_val_if_fail(user
!= NULL
, 0);
2013 cb
= purple_conv_chat_cb_find(chat
, user
);
2016 return PURPLE_CBFLAGS_NONE
;
2021 void purple_conv_chat_set_nick(PurpleConvChat
*chat
, const char *nick
) {
2022 g_return_if_fail(chat
!= NULL
);
2025 chat
->nick
= g_strdup(purple_normalize(chat
->conv
->account
, nick
));
2028 const char *purple_conv_chat_get_nick(PurpleConvChat
*chat
) {
2029 g_return_val_if_fail(chat
!= NULL
, NULL
);
2034 PurpleConversation
*
2035 purple_find_chat(const PurpleConnection
*gc
, int id
)
2038 PurpleConversation
*conv
;
2040 for (l
= purple_get_chats(); l
!= NULL
; l
= l
->next
) {
2041 conv
= (PurpleConversation
*)l
->data
;
2043 if (purple_conv_chat_get_id(PURPLE_CONV_CHAT(conv
)) == id
&&
2044 purple_conversation_get_gc(conv
) == gc
)
2052 purple_conv_chat_left(PurpleConvChat
*chat
)
2054 g_return_if_fail(chat
!= NULL
);
2057 purple_conversation_update(chat
->conv
, PURPLE_CONV_UPDATE_CHATLEFT
);
2061 invite_user_to_chat(gpointer data
, PurpleRequestFields
*fields
)
2063 PurpleConversation
*conv
;
2064 PurpleConvChat
*chat
;
2065 const char *user
, *message
;
2068 chat
= PURPLE_CONV_CHAT(conv
);
2069 user
= purple_request_fields_get_string(fields
, "screenname");
2070 message
= purple_request_fields_get_string(fields
, "message");
2072 serv_chat_invite(purple_conversation_get_gc(conv
), chat
->id
, message
, user
);
2075 void purple_conv_chat_invite_user(PurpleConvChat
*chat
, const char *user
,
2076 const char *message
, gboolean confirm
)
2078 PurpleAccount
*account
;
2079 PurpleConversation
*conv
;
2080 PurpleRequestFields
*fields
;
2081 PurpleRequestFieldGroup
*group
;
2082 PurpleRequestField
*field
;
2084 g_return_if_fail(chat
);
2086 if (!user
|| !*user
|| !message
|| !*message
)
2090 account
= conv
->account
;
2093 serv_chat_invite(purple_account_get_connection(account
),
2094 purple_conv_chat_get_id(chat
), message
, user
);
2098 fields
= purple_request_fields_new();
2099 group
= purple_request_field_group_new(_("Invite to chat"));
2100 purple_request_fields_add_group(fields
, group
);
2102 field
= purple_request_field_string_new("screenname", _("Buddy"), user
, FALSE
);
2103 purple_request_field_group_add_field(group
, field
);
2104 purple_request_field_set_required(field
, TRUE
);
2105 purple_request_field_set_type_hint(field
, "screenname");
2107 field
= purple_request_field_string_new("message", _("Message"), message
, FALSE
);
2108 purple_request_field_group_add_field(group
, field
);
2110 purple_request_fields(conv
, _("Invite to chat"), NULL
,
2111 _("Please enter the name of the user you wish to invite, "
2112 "along with an optional invite message."),
2114 _("Invite"), G_CALLBACK(invite_user_to_chat
),
2116 account
, user
, conv
,
2121 purple_conv_chat_has_left(PurpleConvChat
*chat
)
2123 g_return_val_if_fail(chat
!= NULL
, TRUE
);
2128 PurpleConvChatBuddy
*
2129 purple_conv_chat_cb_new(const char *name
, const char *alias
, PurpleConvChatBuddyFlags flags
)
2131 PurpleConvChatBuddy
*cb
;
2133 g_return_val_if_fail(name
!= NULL
, NULL
);
2135 cb
= g_new0(PurpleConvChatBuddy
, 1);
2136 cb
->name
= g_strdup(name
);
2138 cb
->alias
= g_strdup(alias
);
2139 cb
->attributes
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
2142 PURPLE_DBUS_REGISTER_POINTER(cb
, PurpleConvChatBuddy
);
2146 PurpleConvChatBuddy
*
2147 purple_conv_chat_cb_find(PurpleConvChat
*chat
, const char *name
)
2150 PurpleConvChatBuddy
*cb
= NULL
;
2152 g_return_val_if_fail(chat
!= NULL
, NULL
);
2153 g_return_val_if_fail(name
!= NULL
, NULL
);
2155 for (l
= purple_conv_chat_get_users(chat
); l
; l
= l
->next
) {
2157 if (!g_utf8_collate(cb
->name
, name
))
2165 purple_conv_chat_cb_destroy(PurpleConvChatBuddy
*cb
)
2171 g_free(cb
->alias_key
);
2173 g_hash_table_destroy(cb
->attributes
);
2175 PURPLE_DBUS_UNREGISTER_POINTER(cb
);
2180 purple_conv_chat_cb_get_name(PurpleConvChatBuddy
*cb
)
2182 g_return_val_if_fail(cb
!= NULL
, NULL
);
2188 purple_conv_chat_cb_get_attribute(PurpleConvChatBuddy
*cb
, const char *key
)
2190 g_return_val_if_fail(cb
!= NULL
, NULL
);
2191 g_return_val_if_fail(key
!= NULL
, NULL
);
2193 return g_hash_table_lookup(cb
->attributes
, key
);
2197 append_attribute_key(gpointer key
, gpointer value
, gpointer user_data
)
2199 GList
**list
= user_data
;
2200 *list
= g_list_prepend(*list
, key
);
2204 purple_conv_chat_cb_get_attribute_keys(PurpleConvChatBuddy
*cb
)
2208 g_return_val_if_fail(cb
!= NULL
, NULL
);
2210 g_hash_table_foreach(cb
->attributes
, (GHFunc
)append_attribute_key
, &keys
);
2216 purple_conv_chat_cb_set_attribute(PurpleConvChat
*chat
, PurpleConvChatBuddy
*cb
, const char *key
, const char *value
)
2218 PurpleConversation
*conv
;
2219 PurpleConversationUiOps
*ops
;
2221 g_return_if_fail(cb
!= NULL
);
2222 g_return_if_fail(key
!= NULL
);
2223 g_return_if_fail(value
!= NULL
);
2225 g_hash_table_replace(cb
->attributes
, g_strdup(key
), g_strdup(value
));
2227 conv
= purple_conv_chat_get_conversation(chat
);
2228 ops
= purple_conversation_get_ui_ops(conv
);
2230 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
2231 ops
->chat_update_user(conv
, cb
->name
);
2235 purple_conv_chat_cb_set_attributes(PurpleConvChat
*chat
, PurpleConvChatBuddy
*cb
, GList
*keys
, GList
*values
)
2237 PurpleConversation
*conv
;
2238 PurpleConversationUiOps
*ops
;
2240 g_return_if_fail(cb
!= NULL
);
2241 g_return_if_fail(keys
!= NULL
);
2242 g_return_if_fail(values
!= NULL
);
2244 while (keys
!= NULL
&& values
!= NULL
) {
2245 g_hash_table_replace(cb
->attributes
, g_strdup(keys
->data
), g_strdup(values
->data
));
2246 keys
= g_list_next(keys
);
2247 values
= g_list_next(values
);
2250 conv
= purple_conv_chat_get_conversation(chat
);
2251 ops
= purple_conversation_get_ui_ops(conv
);
2253 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
2254 ops
->chat_update_user(conv
, cb
->name
);
2258 purple_conversation_get_extended_menu(PurpleConversation
*conv
)
2262 g_return_val_if_fail(conv
!= NULL
, NULL
);
2264 purple_signal_emit(purple_conversations_get_handle(),
2265 "conversation-extended-menu", conv
, &menu
);
2269 void purple_conversation_clear_message_history(PurpleConversation
*conv
)
2271 GList
*list
= conv
->message_history
;
2272 message_history_free(list
);
2273 conv
->message_history
= NULL
;
2275 purple_signal_emit(purple_conversations_get_handle(),
2276 "cleared-message-history", conv
);
2279 GList
*purple_conversation_get_message_history(PurpleConversation
*conv
)
2281 return conv
->message_history
;
2284 const char *purple_conversation_message_get_sender(PurpleConvMessage
*msg
)
2286 g_return_val_if_fail(msg
, NULL
);
2290 const char *purple_conversation_message_get_message(PurpleConvMessage
*msg
)
2292 g_return_val_if_fail(msg
, NULL
);
2296 PurpleMessageFlags
purple_conversation_message_get_flags(PurpleConvMessage
*msg
)
2298 g_return_val_if_fail(msg
, 0);
2302 time_t purple_conversation_message_get_timestamp(PurpleConvMessage
*msg
)
2304 g_return_val_if_fail(msg
, 0);
2309 purple_conversation_do_command(PurpleConversation
*conv
, const gchar
*cmdline
,
2310 const gchar
*markup
, gchar
**error
)
2312 char *mark
= (markup
&& *markup
) ? NULL
: g_markup_escape_text(cmdline
, -1), *err
= NULL
;
2313 PurpleCmdStatus status
= purple_cmd_do_command(conv
, cmdline
, mark
? mark
: markup
, error
? error
: &err
);
2316 return (status
== PURPLE_CMD_STATUS_OK
);
2320 purple_conversations_get_handle(void)
2328 purple_conversations_init(void)
2330 void *handle
= purple_conversations_get_handle();
2332 conversation_cache
= g_hash_table_new_full((GHashFunc
)_purple_conversations_hconv_hash
,
2333 (GEqualFunc
)_purple_conversations_hconv_equal
,
2334 (GDestroyNotify
)_purple_conversations_hconv_free_key
, NULL
);
2336 /**********************************************************************
2337 * Register preferences
2338 **********************************************************************/
2341 purple_prefs_add_none("/purple/conversations");
2343 /* Conversations -> Chat */
2344 purple_prefs_add_none("/purple/conversations/chat");
2345 purple_prefs_add_bool("/purple/conversations/chat/show_nick_change", TRUE
);
2347 /* Conversations -> IM */
2348 purple_prefs_add_none("/purple/conversations/im");
2349 purple_prefs_add_bool("/purple/conversations/im/send_typing", TRUE
);
2352 /**********************************************************************
2354 **********************************************************************/
2355 purple_signal_register(handle
, "writing-im-msg",
2356 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT
,
2357 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2358 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2359 PURPLE_SUBTYPE_ACCOUNT
),
2360 purple_value_new(PURPLE_TYPE_STRING
),
2361 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2362 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2363 PURPLE_SUBTYPE_CONVERSATION
),
2364 purple_value_new(PURPLE_TYPE_UINT
));
2366 purple_signal_register(handle
, "wrote-im-msg",
2367 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2369 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2370 PURPLE_SUBTYPE_ACCOUNT
),
2371 purple_value_new(PURPLE_TYPE_STRING
),
2372 purple_value_new(PURPLE_TYPE_STRING
),
2373 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2374 PURPLE_SUBTYPE_CONVERSATION
),
2375 purple_value_new(PURPLE_TYPE_UINT
));
2377 purple_signal_register(handle
, "sent-attention",
2378 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT
,
2380 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2381 PURPLE_SUBTYPE_ACCOUNT
),
2382 purple_value_new(PURPLE_TYPE_STRING
),
2383 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2384 PURPLE_SUBTYPE_CONVERSATION
),
2385 purple_value_new(PURPLE_TYPE_UINT
));
2387 purple_signal_register(handle
, "got-attention",
2388 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT
,
2390 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2391 PURPLE_SUBTYPE_ACCOUNT
),
2392 purple_value_new(PURPLE_TYPE_STRING
),
2393 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2394 PURPLE_SUBTYPE_CONVERSATION
),
2395 purple_value_new(PURPLE_TYPE_UINT
));
2397 purple_signal_register(handle
, "sending-im-msg",
2398 purple_marshal_VOID__POINTER_POINTER_POINTER
,
2400 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2401 PURPLE_SUBTYPE_ACCOUNT
),
2402 purple_value_new(PURPLE_TYPE_STRING
),
2403 purple_value_new_outgoing(PURPLE_TYPE_STRING
));
2405 purple_signal_register(handle
, "sent-im-msg",
2406 purple_marshal_VOID__POINTER_POINTER_POINTER
,
2408 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2409 PURPLE_SUBTYPE_ACCOUNT
),
2410 purple_value_new(PURPLE_TYPE_STRING
),
2411 purple_value_new(PURPLE_TYPE_STRING
));
2413 purple_signal_register(handle
, "receiving-im-msg",
2414 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER
,
2415 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2416 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2417 PURPLE_SUBTYPE_ACCOUNT
),
2418 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2419 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2420 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2421 PURPLE_SUBTYPE_CONVERSATION
),
2422 purple_value_new_outgoing(PURPLE_TYPE_UINT
));
2424 purple_signal_register(handle
, "received-im-msg",
2425 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2427 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2428 PURPLE_SUBTYPE_ACCOUNT
),
2429 purple_value_new(PURPLE_TYPE_STRING
),
2430 purple_value_new(PURPLE_TYPE_STRING
),
2431 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2432 PURPLE_SUBTYPE_CONVERSATION
),
2433 purple_value_new(PURPLE_TYPE_UINT
));
2435 purple_signal_register(handle
, "blocked-im-msg",
2436 purple_marshal_VOID__POINTER_POINTER_POINTER_UINT_UINT
,
2438 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2439 PURPLE_SUBTYPE_ACCOUNT
),
2440 purple_value_new(PURPLE_TYPE_STRING
),
2441 purple_value_new(PURPLE_TYPE_STRING
),
2442 purple_value_new(PURPLE_TYPE_UINT
),
2443 purple_value_new(PURPLE_TYPE_UINT
));
2445 purple_signal_register(handle
, "writing-chat-msg",
2446 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_UINT
,
2447 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2448 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2449 PURPLE_SUBTYPE_ACCOUNT
),
2450 purple_value_new(PURPLE_TYPE_STRING
),
2451 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2452 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2453 PURPLE_SUBTYPE_CONVERSATION
),
2454 purple_value_new(PURPLE_TYPE_UINT
));
2456 purple_signal_register(handle
, "wrote-chat-msg",
2457 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2459 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2460 PURPLE_SUBTYPE_ACCOUNT
),
2461 purple_value_new(PURPLE_TYPE_STRING
),
2462 purple_value_new(PURPLE_TYPE_STRING
),
2463 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2464 PURPLE_SUBTYPE_CONVERSATION
),
2465 purple_value_new(PURPLE_TYPE_UINT
));
2467 purple_signal_register(handle
, "sending-chat-msg",
2468 purple_marshal_VOID__POINTER_POINTER_UINT
, NULL
, 3,
2469 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2470 PURPLE_SUBTYPE_ACCOUNT
),
2471 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2472 purple_value_new(PURPLE_TYPE_UINT
));
2474 purple_signal_register(handle
, "sent-chat-msg",
2475 purple_marshal_VOID__POINTER_POINTER_UINT
, NULL
, 3,
2476 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2477 PURPLE_SUBTYPE_ACCOUNT
),
2478 purple_value_new(PURPLE_TYPE_STRING
),
2479 purple_value_new(PURPLE_TYPE_UINT
));
2481 purple_signal_register(handle
, "receiving-chat-msg",
2482 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER
,
2483 purple_value_new(PURPLE_TYPE_BOOLEAN
), 5,
2484 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2485 PURPLE_SUBTYPE_ACCOUNT
),
2486 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2487 purple_value_new_outgoing(PURPLE_TYPE_STRING
),
2488 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2489 PURPLE_SUBTYPE_CONVERSATION
),
2490 purple_value_new_outgoing(PURPLE_TYPE_UINT
));
2492 purple_signal_register(handle
, "received-chat-msg",
2493 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_UINT
,
2495 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2496 PURPLE_SUBTYPE_ACCOUNT
),
2497 purple_value_new(PURPLE_TYPE_STRING
),
2498 purple_value_new(PURPLE_TYPE_STRING
),
2499 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2500 PURPLE_SUBTYPE_CONVERSATION
),
2501 purple_value_new(PURPLE_TYPE_UINT
));
2503 purple_signal_register(handle
, "conversation-created",
2504 purple_marshal_VOID__POINTER
, NULL
, 1,
2505 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2506 PURPLE_SUBTYPE_CONVERSATION
));
2508 purple_signal_register(handle
, "conversation-updated",
2509 purple_marshal_VOID__POINTER_UINT
, NULL
, 2,
2510 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2511 PURPLE_SUBTYPE_CONVERSATION
),
2512 purple_value_new(PURPLE_TYPE_UINT
));
2514 purple_signal_register(handle
, "deleting-conversation",
2515 purple_marshal_VOID__POINTER
, NULL
, 1,
2516 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2517 PURPLE_SUBTYPE_CONVERSATION
));
2519 purple_signal_register(handle
, "buddy-typing",
2520 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2521 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2522 PURPLE_SUBTYPE_ACCOUNT
),
2523 purple_value_new(PURPLE_TYPE_STRING
));
2525 purple_signal_register(handle
, "buddy-typed",
2526 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2527 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2528 PURPLE_SUBTYPE_ACCOUNT
),
2529 purple_value_new(PURPLE_TYPE_STRING
));
2531 purple_signal_register(handle
, "buddy-typing-stopped",
2532 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2533 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2534 PURPLE_SUBTYPE_ACCOUNT
),
2535 purple_value_new(PURPLE_TYPE_STRING
));
2537 purple_signal_register(handle
, "chat-buddy-joining",
2538 purple_marshal_BOOLEAN__POINTER_POINTER_UINT
,
2539 purple_value_new(PURPLE_TYPE_BOOLEAN
), 3,
2540 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2541 PURPLE_SUBTYPE_CONVERSATION
),
2542 purple_value_new(PURPLE_TYPE_STRING
),
2543 purple_value_new(PURPLE_TYPE_UINT
));
2545 purple_signal_register(handle
, "chat-buddy-joined",
2546 purple_marshal_VOID__POINTER_POINTER_UINT_UINT
, NULL
, 4,
2547 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2548 PURPLE_SUBTYPE_CONVERSATION
),
2549 purple_value_new(PURPLE_TYPE_STRING
),
2550 purple_value_new(PURPLE_TYPE_UINT
),
2551 purple_value_new(PURPLE_TYPE_BOOLEAN
));
2553 purple_signal_register(handle
, "chat-buddy-flags",
2554 purple_marshal_VOID__POINTER_POINTER_UINT_UINT
, NULL
, 4,
2555 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2556 PURPLE_SUBTYPE_CONVERSATION
),
2557 purple_value_new(PURPLE_TYPE_STRING
),
2558 purple_value_new(PURPLE_TYPE_UINT
),
2559 purple_value_new(PURPLE_TYPE_UINT
));
2561 purple_signal_register(handle
, "chat-buddy-leaving",
2562 purple_marshal_BOOLEAN__POINTER_POINTER_POINTER
,
2563 purple_value_new(PURPLE_TYPE_BOOLEAN
), 3,
2564 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2565 PURPLE_SUBTYPE_CONVERSATION
),
2566 purple_value_new(PURPLE_TYPE_STRING
),
2567 purple_value_new(PURPLE_TYPE_STRING
));
2569 purple_signal_register(handle
, "chat-buddy-left",
2570 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2571 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2572 PURPLE_SUBTYPE_CONVERSATION
),
2573 purple_value_new(PURPLE_TYPE_STRING
),
2574 purple_value_new(PURPLE_TYPE_STRING
));
2576 purple_signal_register(handle
, "chat-inviting-user",
2577 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2578 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2579 PURPLE_SUBTYPE_CONVERSATION
),
2580 purple_value_new(PURPLE_TYPE_STRING
),
2581 purple_value_new_outgoing(PURPLE_TYPE_STRING
));
2583 purple_signal_register(handle
, "chat-invited-user",
2584 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2585 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2586 PURPLE_SUBTYPE_CONVERSATION
),
2587 purple_value_new(PURPLE_TYPE_STRING
),
2588 purple_value_new(PURPLE_TYPE_STRING
));
2590 purple_signal_register(handle
, "chat-invited",
2591 purple_marshal_INT__POINTER_POINTER_POINTER_POINTER_POINTER
,
2592 purple_value_new(PURPLE_TYPE_INT
), 5,
2593 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2594 PURPLE_SUBTYPE_ACCOUNT
),
2595 purple_value_new(PURPLE_TYPE_STRING
),
2596 purple_value_new(PURPLE_TYPE_STRING
),
2597 purple_value_new(PURPLE_TYPE_STRING
),
2598 purple_value_new(PURPLE_TYPE_POINTER
));
2600 purple_signal_register(handle
, "chat-invite-blocked",
2601 purple_marshal_VOID__POINTER_POINTER_POINTER_POINTER_POINTER
,
2603 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2604 PURPLE_SUBTYPE_ACCOUNT
),
2605 purple_value_new(PURPLE_TYPE_STRING
),
2606 purple_value_new(PURPLE_TYPE_STRING
),
2607 purple_value_new(PURPLE_TYPE_STRING
),
2608 purple_value_new(PURPLE_TYPE_BOXED
, "GHashTable *"));
2610 purple_signal_register(handle
, "chat-joined",
2611 purple_marshal_VOID__POINTER
, NULL
, 1,
2612 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2613 PURPLE_SUBTYPE_CONVERSATION
));
2615 purple_signal_register(handle
, "chat-join-failed",
2616 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2617 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2618 PURPLE_SUBTYPE_CONNECTION
),
2619 purple_value_new(PURPLE_TYPE_POINTER
));
2621 purple_signal_register(handle
, "chat-left",
2622 purple_marshal_VOID__POINTER
, NULL
, 1,
2623 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2624 PURPLE_SUBTYPE_CONVERSATION
));
2626 purple_signal_register(handle
, "chat-topic-changed",
2627 purple_marshal_VOID__POINTER_POINTER_POINTER
, NULL
, 3,
2628 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2629 PURPLE_SUBTYPE_CONVERSATION
),
2630 purple_value_new(PURPLE_TYPE_STRING
),
2631 purple_value_new(PURPLE_TYPE_STRING
));
2633 purple_signal_register(handle
, "cleared-message-history",
2634 purple_marshal_VOID__POINTER
, NULL
, 1,
2635 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2636 PURPLE_SUBTYPE_CONVERSATION
));
2638 purple_signal_register(handle
, "conversation-extended-menu",
2639 purple_marshal_VOID__POINTER_POINTER
, NULL
, 2,
2640 purple_value_new(PURPLE_TYPE_SUBTYPE
,
2641 PURPLE_SUBTYPE_CONVERSATION
),
2642 purple_value_new(PURPLE_TYPE_BOXED
, "GList **"));
2646 purple_conversations_uninit(void)
2648 while (conversations
)
2649 purple_conversation_destroy((PurpleConversation
*)conversations
->data
);
2650 g_hash_table_destroy(conversation_cache
);
2651 purple_signals_unregister_by_instance(purple_conversations_get_handle());