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
23 #include "glibcompat.h"
24 #include "conversationtypes.h"
28 #define SEND_TYPED_TIMEOUT_SECONDS 5
30 /**************************************************************************/
31 /* PurpleIMConversation */
32 /**************************************************************************/
35 * Data specific to Instant Messages.
39 PurpleIMTypingState typing_state
; /* The current typing state. */
40 guint typing_timeout
; /* The typing timer handle. */
41 time_t type_again
; /* The type again time. */
42 guint send_typed_timeout
; /* The type again timer handle. */
43 PurpleBuddyIcon
*icon
; /* The buddy icon. */
44 } PurpleIMConversationPrivate
;
46 /* IM Property enums */
54 static GParamSpec
*im_properties
[IM_PROP_LAST
];
56 G_DEFINE_TYPE_WITH_PRIVATE(PurpleIMConversation
, purple_im_conversation
,
57 PURPLE_TYPE_CONVERSATION
);
59 /**************************************************************************/
60 /* PurpleChatConversation */
61 /**************************************************************************/
64 * Data specific to Chats.
68 GList
*ignored
; /* Ignored users. */
69 char *who
; /* The person who set the topic. */
70 char *topic
; /* The topic. */
71 int id
; /* The chat ID. */
72 char *nick
; /* Your nick in this chat. */
73 gboolean left
; /* We left the chat and kept the window open */
74 GHashTable
*users
; /* Hash table of the users in the room. */
75 } PurpleChatConversationPrivate
;
77 /* Chat Property enums */
88 static GParamSpec
*chat_properties
[CHAT_PROP_LAST
];
90 G_DEFINE_TYPE_WITH_PRIVATE(PurpleChatConversation
, purple_chat_conversation
,
91 PURPLE_TYPE_CONVERSATION
);
93 /**************************************************************************/
95 /**************************************************************************/
99 * @ui_data: The UI data associated with this chat user.
101 * Structure representing a chat user instance.
103 struct _PurpleChatUser
112 * Data for "Chat Buddies"
116 PurpleChatConversation
*chat
; /* The chat */
117 char *name
; /* The chat participant's name in the
119 char *alias
; /* The chat participant's alias, if known;
121 char *alias_key
; /* A string by which this user will be
122 sorted, or @c NULL if the user should be
124 (This is currently always NULL. */
125 gboolean buddy
; /* TRUE if this chat participant is on
126 the buddy list; FALSE otherwise. */
127 PurpleChatUserFlags flags
; /* A bitwise OR of flags for this
128 participant, such as whether they
129 are a channel operator. */
130 } PurpleChatUserPrivate
;
132 /* Chat User Property enums */
142 static GParamSpec
*cu_properties
[CU_PROP_LAST
];
144 G_DEFINE_TYPE_WITH_PRIVATE(PurpleChatUser
, purple_chat_user
,
147 static int purple_chat_user_compare(PurpleChatUser
*a
,
150 /**************************************************************************
151 * IM Conversation API
152 **************************************************************************/
154 reset_typing_cb(gpointer data
)
156 PurpleIMConversation
*im
= (PurpleIMConversation
*)data
;
158 purple_im_conversation_set_typing_state(im
, PURPLE_IM_NOT_TYPING
);
159 purple_im_conversation_stop_typing_timeout(im
);
165 send_typed_cb(gpointer data
)
167 PurpleIMConversation
*im
= PURPLE_IM_CONVERSATION(data
);
168 PurpleConnection
*gc
;
171 g_return_val_if_fail(im
!= NULL
, FALSE
);
173 gc
= purple_conversation_get_connection(PURPLE_CONVERSATION(im
));
174 name
= purple_conversation_get_name(PURPLE_CONVERSATION(im
));
176 if (gc
!= NULL
&& name
!= NULL
) {
177 /* We set this to 1 so that PURPLE_IM_TYPING will be sent
178 * if the Purple user types anything else.
180 purple_im_conversation_set_type_again(im
, 1);
182 purple_serv_send_typing(gc
, name
, PURPLE_IM_TYPED
);
184 purple_debug(PURPLE_DEBUG_MISC
, "conversationtypes", "typed...\n");
191 purple_im_conversation_set_icon(PurpleIMConversation
*im
, PurpleBuddyIcon
*icon
)
193 PurpleIMConversationPrivate
*priv
= NULL
;
195 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
197 priv
= purple_im_conversation_get_instance_private(im
);
198 if (priv
->icon
!= icon
)
200 purple_buddy_icon_unref(priv
->icon
);
202 priv
->icon
= (icon
== NULL
? NULL
: purple_buddy_icon_ref(icon
));
204 g_object_notify_by_pspec(G_OBJECT(im
), im_properties
[IM_PROP_ICON
]);
207 purple_conversation_update(PURPLE_CONVERSATION(im
),
208 PURPLE_CONVERSATION_UPDATE_ICON
);
212 purple_im_conversation_get_icon(PurpleIMConversation
*im
)
214 PurpleIMConversationPrivate
*priv
= NULL
;
216 g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im
), NULL
);
218 priv
= purple_im_conversation_get_instance_private(im
);
223 purple_im_conversation_set_typing_state(PurpleIMConversation
*im
, PurpleIMTypingState state
)
225 PurpleIMConversationPrivate
*priv
= NULL
;
226 PurpleAccount
*account
;
229 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
231 priv
= purple_im_conversation_get_instance_private(im
);
232 name
= purple_conversation_get_name(PURPLE_CONVERSATION(im
));
233 account
= purple_conversation_get_account(PURPLE_CONVERSATION(im
));
235 if (priv
->typing_state
!= state
)
237 priv
->typing_state
= state
;
239 g_object_notify_by_pspec(G_OBJECT(im
),
240 im_properties
[IM_PROP_TYPING_STATE
]);
244 case PURPLE_IM_TYPING
:
245 purple_signal_emit(purple_conversations_get_handle(),
246 "buddy-typing", account
, name
);
248 case PURPLE_IM_TYPED
:
249 purple_signal_emit(purple_conversations_get_handle(),
250 "buddy-typed", account
, name
);
252 case PURPLE_IM_NOT_TYPING
:
253 purple_signal_emit(purple_conversations_get_handle(),
254 "buddy-typing-stopped", account
, name
);
258 purple_im_conversation_update_typing(im
);
263 purple_im_conversation_get_typing_state(PurpleIMConversation
*im
)
265 PurpleIMConversationPrivate
*priv
= NULL
;
267 g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im
), 0);
269 priv
= purple_im_conversation_get_instance_private(im
);
270 return priv
->typing_state
;
274 purple_im_conversation_start_typing_timeout(PurpleIMConversation
*im
, int timeout
)
276 PurpleIMConversationPrivate
*priv
= NULL
;
278 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
280 priv
= purple_im_conversation_get_instance_private(im
);
281 if (priv
->typing_timeout
> 0)
282 purple_im_conversation_stop_typing_timeout(im
);
284 priv
->typing_timeout
= g_timeout_add_seconds(timeout
, reset_typing_cb
, im
);
288 purple_im_conversation_stop_typing_timeout(PurpleIMConversation
*im
)
290 PurpleIMConversationPrivate
*priv
= NULL
;
292 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
294 priv
= purple_im_conversation_get_instance_private(im
);
295 if (priv
->typing_timeout
== 0)
298 g_source_remove(priv
->typing_timeout
);
299 priv
->typing_timeout
= 0;
303 purple_im_conversation_get_typing_timeout(PurpleIMConversation
*im
)
305 PurpleIMConversationPrivate
*priv
= NULL
;
307 g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im
), 0);
309 priv
= purple_im_conversation_get_instance_private(im
);
310 return priv
->typing_timeout
;
314 purple_im_conversation_set_type_again(PurpleIMConversation
*im
, unsigned int val
)
316 PurpleIMConversationPrivate
*priv
= NULL
;
318 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
320 priv
= purple_im_conversation_get_instance_private(im
);
322 priv
->type_again
= 0;
324 priv
->type_again
= time(NULL
) + val
;
328 purple_im_conversation_get_type_again(PurpleIMConversation
*im
)
330 PurpleIMConversationPrivate
*priv
= NULL
;
332 g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im
), 0);
334 priv
= purple_im_conversation_get_instance_private(im
);
335 return priv
->type_again
;
339 purple_im_conversation_start_send_typed_timeout(PurpleIMConversation
*im
)
341 PurpleIMConversationPrivate
*priv
= NULL
;
343 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
345 priv
= purple_im_conversation_get_instance_private(im
);
346 priv
->send_typed_timeout
= g_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS
,
351 purple_im_conversation_stop_send_typed_timeout(PurpleIMConversation
*im
)
353 PurpleIMConversationPrivate
*priv
= NULL
;
355 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
357 priv
= purple_im_conversation_get_instance_private(im
);
358 if (priv
->send_typed_timeout
== 0)
361 g_source_remove(priv
->send_typed_timeout
);
362 priv
->send_typed_timeout
= 0;
366 purple_im_conversation_get_send_typed_timeout(PurpleIMConversation
*im
)
368 PurpleIMConversationPrivate
*priv
= NULL
;
370 g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im
), 0);
372 priv
= purple_im_conversation_get_instance_private(im
);
373 return priv
->send_typed_timeout
;
377 purple_im_conversation_update_typing(PurpleIMConversation
*im
)
379 g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im
));
381 purple_conversation_update(PURPLE_CONVERSATION(im
),
382 PURPLE_CONVERSATION_UPDATE_TYPING
);
386 im_conversation_write_message(PurpleConversation
*conv
, PurpleMessage
*msg
)
388 PurpleIMConversation
*im
= PURPLE_IM_CONVERSATION(conv
);
391 g_return_if_fail(im
!= NULL
);
392 g_return_if_fail(msg
!= NULL
);
394 is_recv
= (purple_message_get_flags(msg
) & PURPLE_MESSAGE_RECV
);
397 purple_im_conversation_set_typing_state(im
, PURPLE_IM_NOT_TYPING
);
399 _purple_conversation_write_common(conv
, msg
);
402 /**************************************************************************
403 * GObject code for IMs
404 **************************************************************************/
406 /* Set method for GObject properties */
408 purple_im_conversation_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
411 PurpleIMConversation
*im
= PURPLE_IM_CONVERSATION(obj
);
414 case IM_PROP_TYPING_STATE
:
415 purple_im_conversation_set_typing_state(im
, g_value_get_enum(value
));
418 purple_im_conversation_set_icon(im
, g_value_get_pointer(value
));
421 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
426 /* Get method for GObject properties */
428 purple_im_conversation_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
431 PurpleIMConversation
*im
= PURPLE_IM_CONVERSATION(obj
);
434 case IM_PROP_TYPING_STATE
:
435 g_value_set_enum(value
, purple_im_conversation_get_typing_state(im
));
438 g_value_set_pointer(value
, purple_im_conversation_get_icon(im
));
441 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
446 /* GObject initialization function */
447 static void purple_im_conversation_init(PurpleIMConversation
*im
)
451 /* Called when done constructing */
453 purple_im_conversation_constructed(GObject
*object
)
455 PurpleIMConversation
*im
= PURPLE_IM_CONVERSATION(object
);
456 PurpleAccount
*account
;
457 PurpleBuddyIcon
*icon
;
460 G_OBJECT_CLASS(purple_im_conversation_parent_class
)->
468 if ((icon
= purple_buddy_icons_find(account
, name
)))
470 purple_im_conversation_set_icon(im
, icon
);
471 /* purple_im_conversation_set_icon refs the icon. */
472 purple_buddy_icon_unref(icon
);
475 if (purple_prefs_get_bool("/purple/logging/log_ims"))
476 purple_conversation_set_logging(PURPLE_CONVERSATION(im
), TRUE
);
478 g_object_unref(account
);
482 /* GObject dispose function */
484 purple_im_conversation_dispose(GObject
*object
)
486 PurpleIMConversationPrivate
*priv
=
487 purple_im_conversation_get_instance_private(
488 PURPLE_IM_CONVERSATION(object
));
491 purple_buddy_icon_unref(priv
->icon
);
495 G_OBJECT_CLASS(purple_im_conversation_parent_class
)->dispose(object
);
498 /* GObject finalize function */
500 purple_im_conversation_finalize(GObject
*object
)
502 PurpleIMConversation
*im
= PURPLE_IM_CONVERSATION(object
);
503 PurpleConnection
*gc
= purple_conversation_get_connection(PURPLE_CONVERSATION(im
));
504 PurpleProtocol
*protocol
= NULL
;
505 const char *name
= purple_conversation_get_name(PURPLE_CONVERSATION(im
));
509 /* Still connected */
510 protocol
= purple_connection_get_protocol(gc
);
512 if (purple_prefs_get_bool("/purple/conversations/im/send_typing"))
513 purple_serv_send_typing(gc
, name
, PURPLE_IM_NOT_TYPING
);
515 purple_protocol_client_iface_convo_closed(protocol
, gc
, name
);
518 purple_im_conversation_stop_typing_timeout(im
);
519 purple_im_conversation_stop_send_typed_timeout(im
);
521 G_OBJECT_CLASS(purple_im_conversation_parent_class
)->finalize(object
);
524 /* Class initializer function */
525 static void purple_im_conversation_class_init(PurpleIMConversationClass
*klass
)
527 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
528 PurpleConversationClass
*conv_class
= PURPLE_CONVERSATION_CLASS(klass
);
530 obj_class
->dispose
= purple_im_conversation_dispose
;
531 obj_class
->finalize
= purple_im_conversation_finalize
;
532 obj_class
->constructed
= purple_im_conversation_constructed
;
534 /* Setup properties */
535 obj_class
->get_property
= purple_im_conversation_get_property
;
536 obj_class
->set_property
= purple_im_conversation_set_property
;
538 conv_class
->write_message
= im_conversation_write_message
;
540 im_properties
[IM_PROP_TYPING_STATE
] =
541 g_param_spec_enum("typing-state", "Typing state",
542 "Status of the user's typing of a message.",
543 PURPLE_TYPE_IM_TYPING_STATE
, PURPLE_IM_NOT_TYPING
,
544 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
546 im_properties
[IM_PROP_ICON
] = g_param_spec_pointer(
547 "icon", "Buddy icon", "The buddy icon for the IM.",
548 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
550 g_object_class_install_properties(obj_class
, IM_PROP_LAST
, im_properties
);
553 PurpleIMConversation
*
554 purple_im_conversation_new(PurpleAccount
*account
, const char *name
)
556 PurpleIMConversation
*im
;
557 PurpleConnection
*gc
;
559 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account
), NULL
);
560 g_return_val_if_fail(name
!= NULL
, NULL
);
562 /* Check if this conversation already exists. */
563 if ((im
= purple_conversations_find_im_with_account(name
, account
)) != NULL
)
566 gc
= purple_account_get_connection(account
);
567 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
569 im
= g_object_new(PURPLE_TYPE_IM_CONVERSATION
,
578 /**************************************************************************
579 * Chat Conversation API
580 **************************************************************************/
582 _purple_conversation_user_hash(gconstpointer data
)
584 const gchar
*name
= data
;
588 collated
= g_utf8_collate_key(name
, -1);
589 hash
= g_str_hash(collated
);
595 _purple_conversation_user_equal(gconstpointer a
, gconstpointer b
)
597 return !g_utf8_collate(a
, b
);
601 purple_chat_conversation_get_users(PurpleChatConversation
*chat
)
603 PurpleChatConversationPrivate
*priv
= NULL
;
605 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
607 priv
= purple_chat_conversation_get_instance_private(chat
);
608 return g_hash_table_get_values(priv
->users
);
612 purple_chat_conversation_get_users_count(PurpleChatConversation
*chat
)
614 PurpleChatConversationPrivate
*priv
= NULL
;
616 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), 0);
618 priv
= purple_chat_conversation_get_instance_private(chat
);
619 return g_hash_table_size(priv
->users
);
623 purple_chat_conversation_ignore(PurpleChatConversation
*chat
, const char *name
)
625 PurpleChatConversationPrivate
*priv
= NULL
;
627 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
628 g_return_if_fail(name
!= NULL
);
630 priv
= purple_chat_conversation_get_instance_private(chat
);
632 /* Make sure the user isn't already ignored. */
633 if (purple_chat_conversation_is_ignored_user(chat
, name
))
636 purple_chat_conversation_set_ignored(chat
,
637 g_list_append(priv
->ignored
, g_strdup(name
)));
641 purple_chat_conversation_unignore(PurpleChatConversation
*chat
, const char *name
)
643 PurpleChatConversationPrivate
*priv
= NULL
;
646 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
647 g_return_if_fail(name
!= NULL
);
649 priv
= purple_chat_conversation_get_instance_private(chat
);
651 /* Make sure the user is actually ignored. */
652 if (!purple_chat_conversation_is_ignored_user(chat
, name
))
655 item
= g_list_find(purple_chat_conversation_get_ignored(chat
),
656 purple_chat_conversation_get_ignored_user(chat
, name
));
658 purple_chat_conversation_set_ignored(chat
,
659 g_list_remove_link(priv
->ignored
, item
));
666 purple_chat_conversation_set_ignored(PurpleChatConversation
*chat
, GList
*ignored
)
668 PurpleChatConversationPrivate
*priv
= NULL
;
670 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
672 priv
= purple_chat_conversation_get_instance_private(chat
);
673 priv
->ignored
= ignored
;
678 purple_chat_conversation_get_ignored(PurpleChatConversation
*chat
)
680 PurpleChatConversationPrivate
*priv
= NULL
;
682 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
684 priv
= purple_chat_conversation_get_instance_private(chat
);
685 return priv
->ignored
;
689 purple_chat_conversation_get_ignored_user(PurpleChatConversation
*chat
, const char *user
)
693 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
694 g_return_val_if_fail(user
!= NULL
, NULL
);
696 for (ignored
= purple_chat_conversation_get_ignored(chat
);
698 ignored
= ignored
->next
) {
700 const char *ign
= (const char *)ignored
->data
;
702 if (!purple_utf8_strcasecmp(user
, ign
) ||
703 ((*ign
== '+' || *ign
== '%') && !purple_utf8_strcasecmp(user
, ign
+ 1)))
709 if ((*ign
== '+' && !purple_utf8_strcasecmp(user
, ign
+ 1)) ||
710 (*ign
!= '+' && !purple_utf8_strcasecmp(user
, ign
)))
719 purple_chat_conversation_is_ignored_user(PurpleChatConversation
*chat
, const char *user
)
721 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), FALSE
);
722 g_return_val_if_fail(user
!= NULL
, FALSE
);
724 return (purple_chat_conversation_get_ignored_user(chat
, user
) != NULL
);
728 purple_chat_conversation_set_topic(PurpleChatConversation
*chat
, const char *who
, const char *topic
)
730 PurpleChatConversationPrivate
*priv
= NULL
;
733 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
735 priv
= purple_chat_conversation_get_instance_private(chat
);
740 priv
->who
= g_strdup(who
);
741 priv
->topic
= g_strdup(topic
);
743 obj
= G_OBJECT(chat
);
744 g_object_freeze_notify(obj
);
745 g_object_notify_by_pspec(obj
, chat_properties
[CHAT_PROP_TOPIC_WHO
]);
746 g_object_notify_by_pspec(obj
, chat_properties
[CHAT_PROP_TOPIC
]);
747 g_object_thaw_notify(obj
);
749 purple_conversation_update(PURPLE_CONVERSATION(chat
),
750 PURPLE_CONVERSATION_UPDATE_TOPIC
);
752 purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed",
753 chat
, priv
->who
, priv
->topic
);
757 purple_chat_conversation_get_topic(PurpleChatConversation
*chat
)
759 PurpleChatConversationPrivate
*priv
= NULL
;
761 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
763 priv
= purple_chat_conversation_get_instance_private(chat
);
768 purple_chat_conversation_get_topic_who(PurpleChatConversation
*chat
)
770 PurpleChatConversationPrivate
*priv
= NULL
;
772 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
774 priv
= purple_chat_conversation_get_instance_private(chat
);
779 purple_chat_conversation_set_id(PurpleChatConversation
*chat
, int id
)
781 PurpleChatConversationPrivate
*priv
= NULL
;
783 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
785 priv
= purple_chat_conversation_get_instance_private(chat
);
788 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_ID
]);
792 purple_chat_conversation_get_id(PurpleChatConversation
*chat
)
794 PurpleChatConversationPrivate
*priv
= NULL
;
796 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), -1);
798 priv
= purple_chat_conversation_get_instance_private(chat
);
803 chat_conversation_write_message(PurpleConversation
*conv
, PurpleMessage
*msg
)
805 PurpleChatConversationPrivate
*priv
= NULL
;
806 PurpleMessageFlags flags
;
808 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv
));
809 g_return_if_fail(msg
!= NULL
);
811 priv
= purple_chat_conversation_get_instance_private(PURPLE_CHAT_CONVERSATION(conv
));
813 /* Don't display this if the person who wrote it is ignored. */
814 if (purple_message_get_author(msg
) && purple_chat_conversation_is_ignored_user(
815 PURPLE_CHAT_CONVERSATION(conv
), purple_message_get_author(msg
)))
820 flags
= purple_message_get_flags(msg
);
821 if (flags
& PURPLE_MESSAGE_RECV
) {
822 if (purple_utf8_has_word(purple_message_get_contents(msg
), priv
->nick
)) {
823 flags
|= PURPLE_MESSAGE_NICK
;
824 purple_message_set_flags(msg
, flags
);
828 _purple_conversation_write_common(conv
, msg
);
832 purple_chat_conversation_add_user(PurpleChatConversation
*chat
, const char *user
,
833 const char *extra_msg
, PurpleChatUserFlags flags
,
834 gboolean new_arrival
)
836 GList
*users
= g_list_append(NULL
, (char *)user
);
837 GList
*extra_msgs
= g_list_append(NULL
, (char *)extra_msg
);
838 GList
*flags2
= g_list_append(NULL
, GINT_TO_POINTER(flags
));
840 purple_chat_conversation_add_users(chat
, users
, extra_msgs
, flags2
, new_arrival
);
843 g_list_free(extra_msgs
);
848 purple_chat_conversation_add_users(PurpleChatConversation
*chat
, GList
*users
, GList
*extra_msgs
,
849 GList
*flags
, gboolean new_arrivals
)
851 PurpleConversation
*conv
;
852 PurpleConversationUiOps
*ops
;
853 PurpleChatUser
*chatuser
;
854 PurpleChatConversationPrivate
*priv
;
855 PurpleAccount
*account
;
856 PurpleConnection
*gc
;
857 PurpleProtocol
*protocol
;
859 GList
*cbuddies
= NULL
;
861 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
862 g_return_if_fail(users
!= NULL
);
864 priv
= purple_chat_conversation_get_instance_private(chat
);
865 conv
= PURPLE_CONVERSATION(chat
);
866 ops
= purple_conversation_get_ui_ops(conv
);
868 account
= purple_conversation_get_account(conv
);
869 gc
= purple_conversation_get_connection(conv
);
870 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
871 protocol
= purple_connection_get_protocol(gc
);
872 g_return_if_fail(PURPLE_IS_PROTOCOL(protocol
));
876 while ((ul
!= NULL
) && (fl
!= NULL
)) {
877 const char *user
= (const char *)ul
->data
;
878 const char *alias
= user
;
880 PurpleChatUserFlags flag
= GPOINTER_TO_INT(fl
->data
);
881 const char *extra_msg
= (extra_msgs
? extra_msgs
->data
: NULL
);
883 if(!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
884 if (purple_strequal(priv
->nick
, purple_normalize(account
, user
))) {
885 const char *alias2
= purple_account_get_private_alias(account
);
890 const char *display_name
= purple_connection_get_display_name(gc
);
891 if (display_name
!= NULL
)
892 alias
= display_name
;
896 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), user
)) != NULL
)
897 alias
= purple_buddy_get_contact_alias(buddy
);
901 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
902 "chat-user-joining", chat
, user
, flag
)) ||
903 purple_chat_conversation_is_ignored_user(chat
, user
);
905 chatuser
= purple_chat_user_new(chat
, user
, alias
, flag
);
907 g_hash_table_replace(priv
->users
,
908 g_strdup(purple_chat_user_get_name(chatuser
)),
911 cbuddies
= g_list_prepend(cbuddies
, chatuser
);
913 if (!quiet
&& new_arrivals
) {
914 char *alias_esc
= g_markup_escape_text(alias
, -1);
917 if (extra_msg
== NULL
)
918 tmp
= g_strdup_printf(_("%s entered the room."), alias_esc
);
920 char *extra_msg_esc
= g_markup_escape_text(extra_msg
, -1);
921 tmp
= g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
922 alias_esc
, extra_msg_esc
);
923 g_free(extra_msg_esc
);
927 purple_conversation_write_system_message(
928 conv
, tmp
, PURPLE_MESSAGE_NO_LINKIFY
);
932 purple_signal_emit(purple_conversations_get_handle(),
933 "chat-user-joined", chat
, user
, flag
, new_arrivals
);
936 if (extra_msgs
!= NULL
)
937 extra_msgs
= extra_msgs
->next
;
940 cbuddies
= g_list_sort(cbuddies
, (GCompareFunc
)purple_chat_user_compare
);
942 if (ops
!= NULL
&& ops
->chat_add_users
!= NULL
)
943 ops
->chat_add_users(chat
, cbuddies
, new_arrivals
);
945 g_list_free(cbuddies
);
949 purple_chat_conversation_rename_user(PurpleChatConversation
*chat
, const char *old_user
,
950 const char *new_user
)
952 PurpleConversation
*conv
;
953 PurpleConversationUiOps
*ops
;
954 PurpleAccount
*account
;
955 PurpleConnection
*gc
;
956 PurpleProtocol
*protocol
;
958 PurpleChatUserFlags flags
;
959 PurpleChatConversationPrivate
*priv
;
960 const char *new_alias
= new_user
;
962 gboolean is_me
= FALSE
;
964 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
965 g_return_if_fail(old_user
!= NULL
);
966 g_return_if_fail(new_user
!= NULL
);
968 priv
= purple_chat_conversation_get_instance_private(chat
);
969 conv
= PURPLE_CONVERSATION(chat
);
970 ops
= purple_conversation_get_ui_ops(conv
);
971 account
= purple_conversation_get_account(conv
);
973 gc
= purple_conversation_get_connection(conv
);
974 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
975 protocol
= purple_connection_get_protocol(gc
);
976 g_return_if_fail(PURPLE_IS_PROTOCOL(protocol
));
978 if (purple_strequal(priv
->nick
, purple_normalize(account
, old_user
))) {
981 /* Note this for later. */
984 if(!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
985 alias
= purple_account_get_private_alias(account
);
990 const char *display_name
= purple_connection_get_display_name(gc
);
991 if (display_name
!= NULL
)
992 new_alias
= display_name
;
995 } else if (!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
997 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), new_user
)) != NULL
)
998 new_alias
= purple_buddy_get_contact_alias(buddy
);
1001 flags
= purple_chat_user_get_flags(purple_chat_conversation_find_user(chat
, old_user
));
1002 cb
= purple_chat_user_new(chat
, new_user
, new_alias
, flags
);
1004 g_hash_table_replace(priv
->users
,
1005 g_strdup(purple_chat_user_get_name(cb
)), cb
);
1007 if (ops
!= NULL
&& ops
->chat_rename_user
!= NULL
)
1008 ops
->chat_rename_user(chat
, old_user
, new_user
, new_alias
);
1010 cb
= purple_chat_conversation_find_user(chat
, old_user
);
1013 g_hash_table_remove(priv
->users
, purple_chat_user_get_name(cb
));
1015 if (purple_chat_conversation_is_ignored_user(chat
, old_user
)) {
1016 purple_chat_conversation_unignore(chat
, old_user
);
1017 purple_chat_conversation_ignore(chat
, new_user
);
1019 else if (purple_chat_conversation_is_ignored_user(chat
, new_user
))
1020 purple_chat_conversation_unignore(chat
, new_user
);
1023 purple_chat_conversation_set_nick(chat
, new_user
);
1025 if (purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") &&
1026 !purple_chat_conversation_is_ignored_user(chat
, new_user
)) {
1029 char *escaped
= g_markup_escape_text(new_user
, -1);
1030 g_snprintf(tmp
, sizeof(tmp
),
1031 _("You are now known as %s"), escaped
);
1034 const char *old_alias
= old_user
;
1035 const char *new_alias
= new_user
;
1039 if (!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
1042 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), old_user
)) != NULL
)
1043 old_alias
= purple_buddy_get_contact_alias(buddy
);
1044 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), new_user
)) != NULL
)
1045 new_alias
= purple_buddy_get_contact_alias(buddy
);
1048 escaped
= g_markup_escape_text(old_alias
, -1);
1049 escaped2
= g_markup_escape_text(new_alias
, -1);
1050 g_snprintf(tmp
, sizeof(tmp
),
1051 _("%s is now known as %s"), escaped
, escaped2
);
1056 purple_conversation_write_system_message(conv
,
1057 tmp
, PURPLE_MESSAGE_NO_LINKIFY
);
1062 purple_chat_conversation_remove_user(PurpleChatConversation
*chat
, const char *user
, const char *reason
)
1064 GList
*users
= g_list_append(NULL
, (char *)user
);
1066 purple_chat_conversation_remove_users(chat
, users
, reason
);
1072 purple_chat_conversation_remove_users(PurpleChatConversation
*chat
, GList
*users
, const char *reason
)
1074 PurpleConversation
*conv
;
1075 PurpleConnection
*gc
;
1076 PurpleProtocol
*protocol
;
1077 PurpleConversationUiOps
*ops
;
1079 PurpleChatConversationPrivate
*priv
;
1083 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1084 g_return_if_fail(users
!= NULL
);
1086 priv
= purple_chat_conversation_get_instance_private(chat
);
1087 conv
= PURPLE_CONVERSATION(chat
);
1089 gc
= purple_conversation_get_connection(conv
);
1090 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
1091 protocol
= purple_connection_get_protocol(gc
);
1092 g_return_if_fail(PURPLE_IS_PROTOCOL(protocol
));
1094 ops
= purple_conversation_get_ui_ops(conv
);
1096 for (l
= users
; l
!= NULL
; l
= l
->next
) {
1097 const char *user
= (const char *)l
->data
;
1098 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
1099 "chat-user-leaving", chat
, user
, reason
)) |
1100 purple_chat_conversation_is_ignored_user(chat
, user
);
1102 cb
= purple_chat_conversation_find_user(chat
, user
);
1105 g_hash_table_remove(priv
->users
,
1106 purple_chat_user_get_name(cb
));
1109 /* NOTE: Don't remove them from ignored in case they re-enter. */
1112 const char *alias
= user
;
1116 if (!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
1119 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), user
)) != NULL
)
1120 alias
= purple_buddy_get_contact_alias(buddy
);
1123 alias_esc
= g_markup_escape_text(alias
, -1);
1125 if (reason
== NULL
|| !*reason
)
1126 tmp
= g_strdup_printf(_("%s left the room."), alias_esc
);
1128 char *reason_esc
= g_markup_escape_text(reason
, -1);
1129 tmp
= g_strdup_printf(_("%s left the room (%s)."),
1130 alias_esc
, reason_esc
);
1135 purple_conversation_write_system_message(conv
,
1136 tmp
, PURPLE_MESSAGE_NO_LINKIFY
);
1140 purple_signal_emit(purple_conversations_get_handle(), "chat-user-left",
1141 conv
, user
, reason
);
1144 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
)
1145 ops
->chat_remove_users(chat
, users
);
1149 purple_chat_conversation_clear_users(PurpleChatConversation
*chat
)
1151 PurpleChatConversationPrivate
*priv
= NULL
;
1152 PurpleConversationUiOps
*ops
;
1156 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1158 priv
= purple_chat_conversation_get_instance_private(chat
);
1159 ops
= purple_conversation_get_ui_ops(PURPLE_CONVERSATION(chat
));
1161 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
) {
1162 GList
*names
= NULL
;
1164 g_hash_table_iter_init(&it
, priv
->users
);
1165 while (g_hash_table_iter_next(&it
, (gpointer
*)&name
, NULL
))
1166 names
= g_list_prepend(names
, name
);
1168 ops
->chat_remove_users(chat
, names
);
1172 g_hash_table_iter_init(&it
, priv
->users
);
1173 while (g_hash_table_iter_next(&it
, (gpointer
*)&name
, NULL
)) {
1174 purple_signal_emit(purple_conversations_get_handle(),
1175 "chat-user-leaving", chat
, name
, NULL
);
1176 purple_signal_emit(purple_conversations_get_handle(),
1177 "chat-user-left", chat
, name
, NULL
);
1180 g_hash_table_remove_all(priv
->users
);
1183 void purple_chat_conversation_set_nick(PurpleChatConversation
*chat
, const char *nick
) {
1184 PurpleChatConversationPrivate
*priv
= NULL
;
1186 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1188 priv
= purple_chat_conversation_get_instance_private(chat
);
1190 priv
->nick
= g_strdup(purple_normalize(
1191 purple_conversation_get_account(PURPLE_CONVERSATION(chat
)), nick
));
1193 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_NICK
]);
1196 const char *purple_chat_conversation_get_nick(PurpleChatConversation
*chat
) {
1197 PurpleChatConversationPrivate
*priv
= NULL
;
1199 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
1201 priv
= purple_chat_conversation_get_instance_private(chat
);
1206 invite_user_to_chat(gpointer data
, PurpleRequestFields
*fields
)
1208 PurpleConversation
*conv
;
1209 PurpleChatConversationPrivate
*priv
;
1210 const char *user
, *message
;
1213 priv
= purple_chat_conversation_get_instance_private(
1214 PURPLE_CHAT_CONVERSATION(conv
));
1215 user
= purple_request_fields_get_string(fields
, "screenname");
1216 message
= purple_request_fields_get_string(fields
, "message");
1218 purple_serv_chat_invite(purple_conversation_get_connection(conv
), priv
->id
, message
, user
);
1221 void purple_chat_conversation_invite_user(PurpleChatConversation
*chat
, const char *user
,
1222 const char *message
, gboolean confirm
)
1224 PurpleAccount
*account
;
1225 PurpleRequestFields
*fields
;
1226 PurpleRequestFieldGroup
*group
;
1227 PurpleRequestField
*field
;
1229 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1231 if (!user
|| !*user
|| !message
|| !*message
)
1234 account
= purple_conversation_get_account(PURPLE_CONVERSATION(chat
));
1237 purple_serv_chat_invite(purple_account_get_connection(account
),
1238 purple_chat_conversation_get_id(chat
), message
, user
);
1242 fields
= purple_request_fields_new();
1243 group
= purple_request_field_group_new(_("Invite to chat"));
1244 purple_request_fields_add_group(fields
, group
);
1246 field
= purple_request_field_string_new("screenname", _("Buddy"), user
, FALSE
);
1247 purple_request_field_group_add_field(group
, field
);
1248 purple_request_field_set_required(field
, TRUE
);
1249 purple_request_field_set_type_hint(field
, "screenname");
1251 field
= purple_request_field_string_new("message", _("Message"), message
, FALSE
);
1252 purple_request_field_group_add_field(group
, field
);
1254 purple_request_fields(chat
, _("Invite to chat"), NULL
,
1255 _("Please enter the name of the user you wish to invite, "
1256 "along with an optional invite message."),
1258 _("Invite"), G_CALLBACK(invite_user_to_chat
),
1260 purple_request_cpar_from_conversation(PURPLE_CONVERSATION(chat
)),
1265 purple_chat_conversation_has_user(PurpleChatConversation
*chat
, const char *user
)
1267 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), FALSE
);
1268 g_return_val_if_fail(user
!= NULL
, FALSE
);
1270 return (purple_chat_conversation_find_user(chat
, user
) != NULL
);
1274 purple_chat_conversation_leave(PurpleChatConversation
*chat
)
1276 PurpleChatConversationPrivate
*priv
= NULL
;
1278 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1280 priv
= purple_chat_conversation_get_instance_private(chat
);
1283 if (!g_object_get_data(G_OBJECT(chat
), "is-finalizing"))
1284 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_LEFT
]);
1286 purple_conversation_update(PURPLE_CONVERSATION(chat
), PURPLE_CONVERSATION_UPDATE_CHATLEFT
);
1290 purple_chat_conversation_has_left(PurpleChatConversation
*chat
)
1292 PurpleChatConversationPrivate
*priv
= NULL
;
1294 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), TRUE
);
1296 priv
= purple_chat_conversation_get_instance_private(chat
);
1301 chat_conversation_cleanup_for_rejoin(PurpleChatConversation
*chat
)
1304 PurpleAccount
*account
;
1305 PurpleConnection
*gc
;
1306 PurpleConversation
*conv
= PURPLE_CONVERSATION(chat
);
1307 PurpleChatConversationPrivate
*priv
=
1308 purple_chat_conversation_get_instance_private(chat
);
1310 account
= purple_conversation_get_account(conv
);
1312 purple_conversation_close_logs(conv
);
1313 purple_conversation_set_logging(conv
, TRUE
);
1315 gc
= purple_account_get_connection(account
);
1317 if ((disp
= purple_connection_get_display_name(gc
)) != NULL
)
1318 purple_chat_conversation_set_nick(chat
, disp
);
1321 purple_chat_conversation_set_nick(chat
,
1322 purple_account_get_username(account
));
1325 purple_chat_conversation_clear_users(chat
);
1326 purple_chat_conversation_set_topic(chat
, NULL
, NULL
);
1329 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_LEFT
]);
1331 purple_conversation_update(conv
, PURPLE_CONVERSATION_UPDATE_CHATLEFT
);
1335 purple_chat_conversation_find_user(PurpleChatConversation
*chat
, const char *name
)
1337 PurpleChatConversationPrivate
*priv
= NULL
;
1339 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
1340 g_return_val_if_fail(name
!= NULL
, NULL
);
1342 priv
= purple_chat_conversation_get_instance_private(chat
);
1343 return g_hash_table_lookup(priv
->users
, name
);
1346 /**************************************************************************
1347 * GObject code for chats
1348 **************************************************************************/
1350 /* Set method for GObject properties */
1352 purple_chat_conversation_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
1355 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(obj
);
1359 purple_chat_conversation_set_id(chat
, g_value_get_int(value
));
1361 case CHAT_PROP_NICK
:
1362 purple_chat_conversation_set_nick(chat
, g_value_get_string(value
));
1364 case CHAT_PROP_LEFT
:
1366 gboolean left
= g_value_get_boolean(value
);
1368 purple_chat_conversation_leave(chat
);
1372 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1377 /* Get method for GObject properties */
1379 purple_chat_conversation_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
1382 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(obj
);
1385 case CHAT_PROP_TOPIC_WHO
:
1386 g_value_set_string(value
, purple_chat_conversation_get_topic_who(chat
));
1388 case CHAT_PROP_TOPIC
:
1389 g_value_set_string(value
, purple_chat_conversation_get_topic(chat
));
1392 g_value_set_int(value
, purple_chat_conversation_get_id(chat
));
1394 case CHAT_PROP_NICK
:
1395 g_value_set_string(value
, purple_chat_conversation_get_nick(chat
));
1397 case CHAT_PROP_LEFT
:
1398 g_value_set_boolean(value
, purple_chat_conversation_has_left(chat
));
1401 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1406 /* GObject initialization function */
1407 static void purple_chat_conversation_init(PurpleChatConversation
*chat
)
1409 PurpleChatConversationPrivate
*priv
=
1410 purple_chat_conversation_get_instance_private(chat
);
1412 priv
->users
= g_hash_table_new_full(_purple_conversation_user_hash
,
1413 _purple_conversation_user_equal
, g_free
, g_object_unref
);
1416 /* Called when done constructing */
1418 purple_chat_conversation_constructed(GObject
*object
)
1420 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(object
);
1421 PurpleAccount
*account
;
1424 G_OBJECT_CLASS(purple_chat_conversation_parent_class
)->
1425 constructed(object
);
1427 g_object_get(object
, "account", &account
, NULL
);
1429 if ((disp
= purple_connection_get_display_name(purple_account_get_connection(account
))))
1430 purple_chat_conversation_set_nick(chat
, disp
);
1432 purple_chat_conversation_set_nick(chat
,
1433 purple_account_get_username(account
));
1435 if (purple_prefs_get_bool("/purple/logging/log_chats"))
1436 purple_conversation_set_logging(PURPLE_CONVERSATION(chat
), TRUE
);
1438 g_object_unref(account
);
1441 /* GObject dispose function */
1443 purple_chat_conversation_dispose(GObject
*object
)
1445 PurpleChatConversationPrivate
*priv
=
1446 purple_chat_conversation_get_instance_private
1447 (PURPLE_CHAT_CONVERSATION(object
));
1449 g_hash_table_remove_all(priv
->users
);
1451 G_OBJECT_CLASS(purple_chat_conversation_parent_class
)->dispose(object
);
1454 /* GObject finalize function */
1456 purple_chat_conversation_finalize(GObject
*object
)
1458 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(object
);
1459 PurpleConnection
*gc
= purple_conversation_get_connection(PURPLE_CONVERSATION(chat
));
1460 PurpleChatConversationPrivate
*priv
=
1461 purple_chat_conversation_get_instance_private(chat
);
1465 /* Still connected */
1466 int chat_id
= purple_chat_conversation_get_id(chat
);
1469 * Close the window when the user tells us to, and let the protocol
1470 * deal with the internals on it's own time. Don't do this if the
1471 * protocol already knows it left the chat.
1473 if (!purple_chat_conversation_has_left(chat
))
1474 purple_serv_chat_leave(gc
, chat_id
);
1477 * If they didn't call purple_serv_got_chat_left by now, it's too late.
1478 * So we better do it for them before we destroy the thing.
1480 if (!purple_chat_conversation_has_left(chat
))
1481 purple_serv_got_chat_left(gc
, chat_id
);
1484 g_hash_table_destroy(priv
->users
);
1487 g_list_free_full(priv
->ignored
, g_free
);
1488 priv
->ignored
= NULL
;
1491 g_free(priv
->topic
);
1498 G_OBJECT_CLASS(purple_chat_conversation_parent_class
)->finalize(object
);
1501 /* Class initializer function */
1502 static void purple_chat_conversation_class_init(PurpleChatConversationClass
*klass
)
1504 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
1505 PurpleConversationClass
*conv_class
= PURPLE_CONVERSATION_CLASS(klass
);
1507 obj_class
->dispose
= purple_chat_conversation_dispose
;
1508 obj_class
->finalize
= purple_chat_conversation_finalize
;
1509 obj_class
->constructed
= purple_chat_conversation_constructed
;
1511 /* Setup properties */
1512 obj_class
->get_property
= purple_chat_conversation_get_property
;
1513 obj_class
->set_property
= purple_chat_conversation_set_property
;
1515 conv_class
->write_message
= chat_conversation_write_message
;
1517 chat_properties
[CHAT_PROP_TOPIC_WHO
] = g_param_spec_string("topic-who",
1519 "Who set the chat topic.", NULL
,
1520 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
1522 chat_properties
[CHAT_PROP_TOPIC
] = g_param_spec_string("topic",
1524 "Topic of the chat.", NULL
,
1525 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
1527 chat_properties
[CHAT_PROP_ID
] = g_param_spec_int("chat-id",
1529 "The ID of the chat.", G_MININT
, G_MAXINT
, 0,
1530 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1532 chat_properties
[CHAT_PROP_NICK
] = g_param_spec_string("nick",
1534 "The nickname of the user in a chat.", NULL
,
1535 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1537 chat_properties
[CHAT_PROP_LEFT
] = g_param_spec_boolean("left",
1539 "Whether the user has left the chat.", FALSE
,
1540 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1542 g_object_class_install_properties(obj_class
, CHAT_PROP_LAST
,
1546 PurpleChatConversation
*
1547 purple_chat_conversation_new(PurpleAccount
*account
, const char *name
)
1549 PurpleChatConversation
*chat
;
1550 PurpleConnection
*gc
;
1552 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account
), NULL
);
1553 g_return_val_if_fail(name
!= NULL
, NULL
);
1555 /* Check if this conversation already exists. */
1556 if ((chat
= purple_conversations_find_chat_with_account(name
, account
)) != NULL
)
1558 if (!purple_chat_conversation_has_left(chat
)) {
1559 purple_debug_warning("conversationtypes", "Trying to create "
1560 "multiple chats (%s) with the same name is deprecated and "
1561 "will be removed in libpurple 3.0.0", name
);
1564 * This hack is necessary because some protocols (MSN) have unnamed chats
1565 * that all use the same name. A PurpleConversation for one of those
1566 * is only ever re-used if the user has left, so calls to
1567 * purple_conversation_new need to fall-through to creating a new
1569 * TODO 3.0.0: Remove this workaround and mandate unique names.
1572 chat_conversation_cleanup_for_rejoin(chat
);
1577 gc
= purple_account_get_connection(account
);
1578 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
1580 chat
= g_object_new(PURPLE_TYPE_CHAT_CONVERSATION
,
1589 /**************************************************************************
1590 * Chat Conversation User API
1591 **************************************************************************/
1593 purple_chat_user_compare(PurpleChatUser
*a
, PurpleChatUser
*b
)
1595 PurpleChatUserFlags f1
= 0, f2
= 0;
1596 PurpleChatUserPrivate
*priva
, *privb
;
1597 char *user1
= NULL
, *user2
= NULL
;
1600 priva
= purple_chat_user_get_instance_private(a
);
1601 privb
= purple_chat_user_get_instance_private(b
);
1605 if (priva
->alias_key
)
1606 user1
= priva
->alias_key
;
1607 else if (priva
->name
)
1608 user1
= priva
->name
;
1613 if (privb
->alias_key
)
1614 user2
= privb
->alias_key
;
1615 else if (privb
->name
)
1616 user2
= privb
->name
;
1619 if (user1
== NULL
|| user2
== NULL
) {
1620 if (!(user1
== NULL
&& user2
== NULL
))
1621 ret
= (user1
== NULL
) ? -1: 1;
1622 } else if (f1
!= f2
) {
1623 /* sort more important users first */
1624 ret
= (f1
> f2
) ? -1 : 1;
1625 } else if (priva
->buddy
!= privb
->buddy
) {
1626 ret
= priva
->buddy
? -1 : 1;
1628 ret
= purple_utf8_strcasecmp(user1
, user2
);
1635 purple_chat_user_get_alias(PurpleChatUser
*cb
)
1637 PurpleChatUserPrivate
*priv
;
1639 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1641 priv
= purple_chat_user_get_instance_private(cb
);
1646 purple_chat_user_get_name(PurpleChatUser
*cb
)
1648 PurpleChatUserPrivate
*priv
;
1650 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1652 priv
= purple_chat_user_get_instance_private(cb
);
1657 purple_chat_user_set_flags(PurpleChatUser
*cb
,
1658 PurpleChatUserFlags flags
)
1660 PurpleConversationUiOps
*ops
;
1661 PurpleChatUserFlags oldflags
;
1662 PurpleChatUserPrivate
*priv
;
1664 g_return_if_fail(PURPLE_IS_CHAT_USER(cb
));
1666 priv
= purple_chat_user_get_instance_private(cb
);
1668 if (flags
== priv
->flags
)
1671 oldflags
= priv
->flags
;
1672 priv
->flags
= flags
;
1674 g_object_notify_by_pspec(G_OBJECT(cb
), cu_properties
[CU_PROP_FLAGS
]);
1676 ops
= purple_conversation_get_ui_ops(PURPLE_CONVERSATION(priv
->chat
));
1678 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
1679 ops
->chat_update_user(cb
);
1681 purple_signal_emit(purple_conversations_get_handle(),
1682 "chat-user-flags", cb
, oldflags
, flags
);
1686 purple_chat_user_get_flags(PurpleChatUser
*cb
)
1688 PurpleChatUserPrivate
*priv
;
1690 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), PURPLE_CHAT_USER_NONE
);
1692 priv
= purple_chat_user_get_instance_private(cb
);
1697 purple_chat_user_set_ui_data(PurpleChatUser
*cb
, gpointer ui_data
)
1699 g_return_if_fail(PURPLE_IS_CHAT_USER(cb
));
1701 cb
->ui_data
= ui_data
;
1705 purple_chat_user_get_ui_data(PurpleChatUser
*cb
)
1707 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1713 purple_chat_user_set_chat(PurpleChatUser
*cb
,
1714 PurpleChatConversation
*chat
)
1716 PurpleChatUserPrivate
*priv
;
1718 g_return_if_fail(PURPLE_IS_CHAT_USER(cb
));
1720 priv
= purple_chat_user_get_instance_private(cb
);
1723 g_object_notify_by_pspec(G_OBJECT(cb
), cu_properties
[CU_PROP_CHAT
]);
1726 PurpleChatConversation
*
1727 purple_chat_user_get_chat(PurpleChatUser
*cb
)
1729 PurpleChatUserPrivate
*priv
;
1731 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1733 priv
= purple_chat_user_get_instance_private(cb
);
1738 purple_chat_user_is_buddy(PurpleChatUser
*cb
)
1740 PurpleChatUserPrivate
*priv
;
1742 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), FALSE
);
1744 priv
= purple_chat_user_get_instance_private(cb
);
1748 /**************************************************************************
1749 * GObject code for chat user
1750 **************************************************************************/
1752 /* Set method for GObject properties */
1754 purple_chat_user_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
1757 PurpleChatUser
*cb
= PURPLE_CHAT_USER(obj
);
1758 PurpleChatUserPrivate
*priv
=
1759 purple_chat_user_get_instance_private(cb
);
1763 priv
->chat
= g_value_get_object(value
);
1767 priv
->name
= g_value_dup_string(value
);
1770 g_free(priv
->alias
);
1771 priv
->alias
= g_value_dup_string(value
);
1774 priv
->flags
= g_value_get_flags(value
);
1777 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1782 /* Get method for GObject properties */
1784 purple_chat_user_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
1787 PurpleChatUser
*cb
= PURPLE_CHAT_USER(obj
);
1791 g_value_set_object(value
, purple_chat_user_get_chat(cb
));
1794 g_value_set_string(value
, purple_chat_user_get_name(cb
));
1797 g_value_set_string(value
, purple_chat_user_get_alias(cb
));
1800 g_value_set_flags(value
, purple_chat_user_get_flags(cb
));
1803 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1808 /* GObject initialization function */
1810 purple_chat_user_init(PurpleChatUser
*user
)
1814 /* Called when done constructing */
1816 purple_chat_user_constructed(GObject
*object
)
1818 PurpleChatUserPrivate
*priv
= purple_chat_user_get_instance_private(
1819 PURPLE_CHAT_USER(object
));
1820 PurpleAccount
*account
;
1822 G_OBJECT_CLASS(purple_chat_user_parent_class
)->constructed(object
);
1824 account
= purple_conversation_get_account(PURPLE_CONVERSATION(priv
->chat
));
1826 if (purple_blist_find_buddy(account
, priv
->name
) != NULL
)
1830 /* GObject finalize function */
1832 purple_chat_user_finalize(GObject
*object
)
1834 PurpleChatUser
*cb
= PURPLE_CHAT_USER(object
);
1835 PurpleChatUserPrivate
*priv
=
1836 purple_chat_user_get_instance_private(cb
);
1838 purple_signal_emit(purple_conversations_get_handle(),
1839 "deleting-chat-user", cb
);
1841 g_free(priv
->alias
);
1842 g_free(priv
->alias_key
);
1845 G_OBJECT_CLASS(purple_chat_user_parent_class
)->finalize(object
);
1848 /* Class initializer function */
1849 static void purple_chat_user_class_init(PurpleChatUserClass
*klass
)
1851 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
1853 obj_class
->constructed
= purple_chat_user_constructed
;
1854 obj_class
->finalize
= purple_chat_user_finalize
;
1856 /* Setup properties */
1857 obj_class
->get_property
= purple_chat_user_get_property
;
1858 obj_class
->set_property
= purple_chat_user_set_property
;
1860 cu_properties
[CU_PROP_CHAT
] = g_param_spec_object("chat", "Chat",
1861 "The chat the buddy belongs to.", PURPLE_TYPE_CHAT_CONVERSATION
,
1862 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
1863 G_PARAM_STATIC_STRINGS
);
1865 cu_properties
[CU_PROP_NAME
] = g_param_spec_string("name", "Name",
1866 "Name of the chat user.", NULL
,
1867 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
1869 cu_properties
[CU_PROP_ALIAS
] = g_param_spec_string("alias", "Alias",
1870 "Alias of the chat user.", NULL
,
1871 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
1873 cu_properties
[CU_PROP_FLAGS
] = g_param_spec_flags("flags", "Buddy flags",
1874 "The flags for the chat user.",
1875 PURPLE_TYPE_CHAT_USER_FLAGS
, PURPLE_CHAT_USER_NONE
,
1876 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
1878 g_object_class_install_properties(obj_class
, CU_PROP_LAST
, cu_properties
);
1882 purple_chat_user_new(PurpleChatConversation
*chat
, const char *name
,
1883 const char *alias
, PurpleChatUserFlags flags
)
1887 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
1888 g_return_val_if_fail(name
!= NULL
, NULL
);
1890 cb
= g_object_new(PURPLE_TYPE_CHAT_USER
,