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
] = g_param_spec_enum("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
|
545 G_PARAM_STATIC_STRINGS
);
547 im_properties
[IM_PROP_ICON
] = g_param_spec_pointer("icon",
549 "The buddy icon for the IM.",
550 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
|
551 G_PARAM_STATIC_STRINGS
);
553 g_object_class_install_properties(obj_class
, IM_PROP_LAST
, im_properties
);
556 PurpleIMConversation
*
557 purple_im_conversation_new(PurpleAccount
*account
, const char *name
)
559 PurpleIMConversation
*im
;
560 PurpleConnection
*gc
;
562 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account
), NULL
);
563 g_return_val_if_fail(name
!= NULL
, NULL
);
565 /* Check if this conversation already exists. */
566 if ((im
= purple_conversations_find_im_with_account(name
, account
)) != NULL
)
569 gc
= purple_account_get_connection(account
);
570 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
572 im
= g_object_new(PURPLE_TYPE_IM_CONVERSATION
,
581 /**************************************************************************
582 * Chat Conversation API
583 **************************************************************************/
585 _purple_conversation_user_hash(gconstpointer data
)
587 const gchar
*name
= data
;
591 collated
= g_utf8_collate_key(name
, -1);
592 hash
= g_str_hash(collated
);
598 _purple_conversation_user_equal(gconstpointer a
, gconstpointer b
)
600 return !g_utf8_collate(a
, b
);
604 purple_chat_conversation_get_users(PurpleChatConversation
*chat
)
606 PurpleChatConversationPrivate
*priv
= NULL
;
608 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
610 priv
= purple_chat_conversation_get_instance_private(chat
);
611 return g_hash_table_get_values(priv
->users
);
615 purple_chat_conversation_get_users_count(PurpleChatConversation
*chat
)
617 PurpleChatConversationPrivate
*priv
= NULL
;
619 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), 0);
621 priv
= purple_chat_conversation_get_instance_private(chat
);
622 return g_hash_table_size(priv
->users
);
626 purple_chat_conversation_ignore(PurpleChatConversation
*chat
, const char *name
)
628 PurpleChatConversationPrivate
*priv
= NULL
;
630 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
631 g_return_if_fail(name
!= NULL
);
633 priv
= purple_chat_conversation_get_instance_private(chat
);
635 /* Make sure the user isn't already ignored. */
636 if (purple_chat_conversation_is_ignored_user(chat
, name
))
639 purple_chat_conversation_set_ignored(chat
,
640 g_list_append(priv
->ignored
, g_strdup(name
)));
644 purple_chat_conversation_unignore(PurpleChatConversation
*chat
, const char *name
)
646 PurpleChatConversationPrivate
*priv
= NULL
;
649 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
650 g_return_if_fail(name
!= NULL
);
652 priv
= purple_chat_conversation_get_instance_private(chat
);
654 /* Make sure the user is actually ignored. */
655 if (!purple_chat_conversation_is_ignored_user(chat
, name
))
658 item
= g_list_find(purple_chat_conversation_get_ignored(chat
),
659 purple_chat_conversation_get_ignored_user(chat
, name
));
661 purple_chat_conversation_set_ignored(chat
,
662 g_list_remove_link(priv
->ignored
, item
));
669 purple_chat_conversation_set_ignored(PurpleChatConversation
*chat
, GList
*ignored
)
671 PurpleChatConversationPrivate
*priv
= NULL
;
673 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
675 priv
= purple_chat_conversation_get_instance_private(chat
);
676 priv
->ignored
= ignored
;
681 purple_chat_conversation_get_ignored(PurpleChatConversation
*chat
)
683 PurpleChatConversationPrivate
*priv
= NULL
;
685 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
687 priv
= purple_chat_conversation_get_instance_private(chat
);
688 return priv
->ignored
;
692 purple_chat_conversation_get_ignored_user(PurpleChatConversation
*chat
, const char *user
)
696 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
697 g_return_val_if_fail(user
!= NULL
, NULL
);
699 for (ignored
= purple_chat_conversation_get_ignored(chat
);
701 ignored
= ignored
->next
) {
703 const char *ign
= (const char *)ignored
->data
;
705 if (!purple_utf8_strcasecmp(user
, ign
) ||
706 ((*ign
== '+' || *ign
== '%') && !purple_utf8_strcasecmp(user
, ign
+ 1)))
712 if ((*ign
== '+' && !purple_utf8_strcasecmp(user
, ign
+ 1)) ||
713 (*ign
!= '+' && !purple_utf8_strcasecmp(user
, ign
)))
722 purple_chat_conversation_is_ignored_user(PurpleChatConversation
*chat
, const char *user
)
724 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), FALSE
);
725 g_return_val_if_fail(user
!= NULL
, FALSE
);
727 return (purple_chat_conversation_get_ignored_user(chat
, user
) != NULL
);
731 purple_chat_conversation_set_topic(PurpleChatConversation
*chat
, const char *who
, const char *topic
)
733 PurpleChatConversationPrivate
*priv
= NULL
;
736 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
738 priv
= purple_chat_conversation_get_instance_private(chat
);
743 priv
->who
= g_strdup(who
);
744 priv
->topic
= g_strdup(topic
);
746 obj
= G_OBJECT(chat
);
747 g_object_freeze_notify(obj
);
748 g_object_notify_by_pspec(obj
, chat_properties
[CHAT_PROP_TOPIC_WHO
]);
749 g_object_notify_by_pspec(obj
, chat_properties
[CHAT_PROP_TOPIC
]);
750 g_object_thaw_notify(obj
);
752 purple_conversation_update(PURPLE_CONVERSATION(chat
),
753 PURPLE_CONVERSATION_UPDATE_TOPIC
);
755 purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed",
756 chat
, priv
->who
, priv
->topic
);
760 purple_chat_conversation_get_topic(PurpleChatConversation
*chat
)
762 PurpleChatConversationPrivate
*priv
= NULL
;
764 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
766 priv
= purple_chat_conversation_get_instance_private(chat
);
771 purple_chat_conversation_get_topic_who(PurpleChatConversation
*chat
)
773 PurpleChatConversationPrivate
*priv
= NULL
;
775 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
777 priv
= purple_chat_conversation_get_instance_private(chat
);
782 purple_chat_conversation_set_id(PurpleChatConversation
*chat
, int id
)
784 PurpleChatConversationPrivate
*priv
= NULL
;
786 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
788 priv
= purple_chat_conversation_get_instance_private(chat
);
791 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_ID
]);
795 purple_chat_conversation_get_id(PurpleChatConversation
*chat
)
797 PurpleChatConversationPrivate
*priv
= NULL
;
799 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), -1);
801 priv
= purple_chat_conversation_get_instance_private(chat
);
806 chat_conversation_write_message(PurpleConversation
*conv
, PurpleMessage
*msg
)
808 PurpleChatConversationPrivate
*priv
= NULL
;
809 PurpleMessageFlags flags
;
811 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv
));
812 g_return_if_fail(msg
!= NULL
);
814 priv
= purple_chat_conversation_get_instance_private(PURPLE_CHAT_CONVERSATION(conv
));
816 /* Don't display this if the person who wrote it is ignored. */
817 if (purple_message_get_author(msg
) && purple_chat_conversation_is_ignored_user(
818 PURPLE_CHAT_CONVERSATION(conv
), purple_message_get_author(msg
)))
823 flags
= purple_message_get_flags(msg
);
824 if (flags
& PURPLE_MESSAGE_RECV
) {
825 if (purple_utf8_has_word(purple_message_get_contents(msg
), priv
->nick
)) {
826 flags
|= PURPLE_MESSAGE_NICK
;
827 purple_message_set_flags(msg
, flags
);
831 _purple_conversation_write_common(conv
, msg
);
835 purple_chat_conversation_add_user(PurpleChatConversation
*chat
, const char *user
,
836 const char *extra_msg
, PurpleChatUserFlags flags
,
837 gboolean new_arrival
)
839 GList
*users
= g_list_append(NULL
, (char *)user
);
840 GList
*extra_msgs
= g_list_append(NULL
, (char *)extra_msg
);
841 GList
*flags2
= g_list_append(NULL
, GINT_TO_POINTER(flags
));
843 purple_chat_conversation_add_users(chat
, users
, extra_msgs
, flags2
, new_arrival
);
846 g_list_free(extra_msgs
);
851 purple_chat_conversation_add_users(PurpleChatConversation
*chat
, GList
*users
, GList
*extra_msgs
,
852 GList
*flags
, gboolean new_arrivals
)
854 PurpleConversation
*conv
;
855 PurpleConversationUiOps
*ops
;
856 PurpleChatUser
*chatuser
;
857 PurpleChatConversationPrivate
*priv
;
858 PurpleAccount
*account
;
859 PurpleConnection
*gc
;
860 PurpleProtocol
*protocol
;
862 GList
*cbuddies
= NULL
;
864 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
865 g_return_if_fail(users
!= NULL
);
867 priv
= purple_chat_conversation_get_instance_private(chat
);
868 conv
= PURPLE_CONVERSATION(chat
);
869 ops
= purple_conversation_get_ui_ops(conv
);
871 account
= purple_conversation_get_account(conv
);
872 gc
= purple_conversation_get_connection(conv
);
873 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
874 protocol
= purple_connection_get_protocol(gc
);
875 g_return_if_fail(PURPLE_IS_PROTOCOL(protocol
));
879 while ((ul
!= NULL
) && (fl
!= NULL
)) {
880 const char *user
= (const char *)ul
->data
;
881 const char *alias
= user
;
883 PurpleChatUserFlags flag
= GPOINTER_TO_INT(fl
->data
);
884 const char *extra_msg
= (extra_msgs
? extra_msgs
->data
: NULL
);
886 if(!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
887 if (purple_strequal(priv
->nick
, purple_normalize(account
, user
))) {
888 const char *alias2
= purple_account_get_private_alias(account
);
893 const char *display_name
= purple_connection_get_display_name(gc
);
894 if (display_name
!= NULL
)
895 alias
= display_name
;
899 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), user
)) != NULL
)
900 alias
= purple_buddy_get_contact_alias(buddy
);
904 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
905 "chat-user-joining", chat
, user
, flag
)) ||
906 purple_chat_conversation_is_ignored_user(chat
, user
);
908 chatuser
= purple_chat_user_new(chat
, user
, alias
, flag
);
910 g_hash_table_replace(priv
->users
,
911 g_strdup(purple_chat_user_get_name(chatuser
)),
914 cbuddies
= g_list_prepend(cbuddies
, chatuser
);
916 if (!quiet
&& new_arrivals
) {
917 char *alias_esc
= g_markup_escape_text(alias
, -1);
920 if (extra_msg
== NULL
)
921 tmp
= g_strdup_printf(_("%s entered the room."), alias_esc
);
923 char *extra_msg_esc
= g_markup_escape_text(extra_msg
, -1);
924 tmp
= g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
925 alias_esc
, extra_msg_esc
);
926 g_free(extra_msg_esc
);
930 purple_conversation_write_system_message(
931 conv
, tmp
, PURPLE_MESSAGE_NO_LINKIFY
);
935 purple_signal_emit(purple_conversations_get_handle(),
936 "chat-user-joined", chat
, user
, flag
, new_arrivals
);
939 if (extra_msgs
!= NULL
)
940 extra_msgs
= extra_msgs
->next
;
943 cbuddies
= g_list_sort(cbuddies
, (GCompareFunc
)purple_chat_user_compare
);
945 if (ops
!= NULL
&& ops
->chat_add_users
!= NULL
)
946 ops
->chat_add_users(chat
, cbuddies
, new_arrivals
);
948 g_list_free(cbuddies
);
952 purple_chat_conversation_rename_user(PurpleChatConversation
*chat
, const char *old_user
,
953 const char *new_user
)
955 PurpleConversation
*conv
;
956 PurpleConversationUiOps
*ops
;
957 PurpleAccount
*account
;
958 PurpleConnection
*gc
;
959 PurpleProtocol
*protocol
;
961 PurpleChatUserFlags flags
;
962 PurpleChatConversationPrivate
*priv
;
963 const char *new_alias
= new_user
;
965 gboolean is_me
= FALSE
;
967 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
968 g_return_if_fail(old_user
!= NULL
);
969 g_return_if_fail(new_user
!= NULL
);
971 priv
= purple_chat_conversation_get_instance_private(chat
);
972 conv
= PURPLE_CONVERSATION(chat
);
973 ops
= purple_conversation_get_ui_ops(conv
);
974 account
= purple_conversation_get_account(conv
);
976 gc
= purple_conversation_get_connection(conv
);
977 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
978 protocol
= purple_connection_get_protocol(gc
);
979 g_return_if_fail(PURPLE_IS_PROTOCOL(protocol
));
981 if (purple_strequal(priv
->nick
, purple_normalize(account
, old_user
))) {
984 /* Note this for later. */
987 if(!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
988 alias
= purple_account_get_private_alias(account
);
993 const char *display_name
= purple_connection_get_display_name(gc
);
994 if (display_name
!= NULL
)
995 new_alias
= display_name
;
998 } else if (!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
1000 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), new_user
)) != NULL
)
1001 new_alias
= purple_buddy_get_contact_alias(buddy
);
1004 flags
= purple_chat_user_get_flags(purple_chat_conversation_find_user(chat
, old_user
));
1005 cb
= purple_chat_user_new(chat
, new_user
, new_alias
, flags
);
1007 g_hash_table_replace(priv
->users
,
1008 g_strdup(purple_chat_user_get_name(cb
)), cb
);
1010 if (ops
!= NULL
&& ops
->chat_rename_user
!= NULL
)
1011 ops
->chat_rename_user(chat
, old_user
, new_user
, new_alias
);
1013 cb
= purple_chat_conversation_find_user(chat
, old_user
);
1016 g_hash_table_remove(priv
->users
, purple_chat_user_get_name(cb
));
1018 if (purple_chat_conversation_is_ignored_user(chat
, old_user
)) {
1019 purple_chat_conversation_unignore(chat
, old_user
);
1020 purple_chat_conversation_ignore(chat
, new_user
);
1022 else if (purple_chat_conversation_is_ignored_user(chat
, new_user
))
1023 purple_chat_conversation_unignore(chat
, new_user
);
1026 purple_chat_conversation_set_nick(chat
, new_user
);
1028 if (purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") &&
1029 !purple_chat_conversation_is_ignored_user(chat
, new_user
)) {
1032 char *escaped
= g_markup_escape_text(new_user
, -1);
1033 g_snprintf(tmp
, sizeof(tmp
),
1034 _("You are now known as %s"), escaped
);
1037 const char *old_alias
= old_user
;
1038 const char *new_alias
= new_user
;
1042 if (!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
1045 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), old_user
)) != NULL
)
1046 old_alias
= purple_buddy_get_contact_alias(buddy
);
1047 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), new_user
)) != NULL
)
1048 new_alias
= purple_buddy_get_contact_alias(buddy
);
1051 escaped
= g_markup_escape_text(old_alias
, -1);
1052 escaped2
= g_markup_escape_text(new_alias
, -1);
1053 g_snprintf(tmp
, sizeof(tmp
),
1054 _("%s is now known as %s"), escaped
, escaped2
);
1059 purple_conversation_write_system_message(conv
,
1060 tmp
, PURPLE_MESSAGE_NO_LINKIFY
);
1065 purple_chat_conversation_remove_user(PurpleChatConversation
*chat
, const char *user
, const char *reason
)
1067 GList
*users
= g_list_append(NULL
, (char *)user
);
1069 purple_chat_conversation_remove_users(chat
, users
, reason
);
1075 purple_chat_conversation_remove_users(PurpleChatConversation
*chat
, GList
*users
, const char *reason
)
1077 PurpleConversation
*conv
;
1078 PurpleConnection
*gc
;
1079 PurpleProtocol
*protocol
;
1080 PurpleConversationUiOps
*ops
;
1082 PurpleChatConversationPrivate
*priv
;
1086 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1087 g_return_if_fail(users
!= NULL
);
1089 priv
= purple_chat_conversation_get_instance_private(chat
);
1090 conv
= PURPLE_CONVERSATION(chat
);
1092 gc
= purple_conversation_get_connection(conv
);
1093 g_return_if_fail(PURPLE_IS_CONNECTION(gc
));
1094 protocol
= purple_connection_get_protocol(gc
);
1095 g_return_if_fail(PURPLE_IS_PROTOCOL(protocol
));
1097 ops
= purple_conversation_get_ui_ops(conv
);
1099 for (l
= users
; l
!= NULL
; l
= l
->next
) {
1100 const char *user
= (const char *)l
->data
;
1101 quiet
= GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
1102 "chat-user-leaving", chat
, user
, reason
)) |
1103 purple_chat_conversation_is_ignored_user(chat
, user
);
1105 cb
= purple_chat_conversation_find_user(chat
, user
);
1108 g_hash_table_remove(priv
->users
,
1109 purple_chat_user_get_name(cb
));
1112 /* NOTE: Don't remove them from ignored in case they re-enter. */
1115 const char *alias
= user
;
1119 if (!(purple_protocol_get_options(protocol
) & OPT_PROTO_UNIQUE_CHATNAME
)) {
1122 if ((buddy
= purple_blist_find_buddy(purple_connection_get_account(gc
), user
)) != NULL
)
1123 alias
= purple_buddy_get_contact_alias(buddy
);
1126 alias_esc
= g_markup_escape_text(alias
, -1);
1128 if (reason
== NULL
|| !*reason
)
1129 tmp
= g_strdup_printf(_("%s left the room."), alias_esc
);
1131 char *reason_esc
= g_markup_escape_text(reason
, -1);
1132 tmp
= g_strdup_printf(_("%s left the room (%s)."),
1133 alias_esc
, reason_esc
);
1138 purple_conversation_write_system_message(conv
,
1139 tmp
, PURPLE_MESSAGE_NO_LINKIFY
);
1143 purple_signal_emit(purple_conversations_get_handle(), "chat-user-left",
1144 conv
, user
, reason
);
1147 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
)
1148 ops
->chat_remove_users(chat
, users
);
1152 purple_chat_conversation_clear_users(PurpleChatConversation
*chat
)
1154 PurpleChatConversationPrivate
*priv
= NULL
;
1155 PurpleConversationUiOps
*ops
;
1159 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1161 priv
= purple_chat_conversation_get_instance_private(chat
);
1162 ops
= purple_conversation_get_ui_ops(PURPLE_CONVERSATION(chat
));
1164 if (ops
!= NULL
&& ops
->chat_remove_users
!= NULL
) {
1165 GList
*names
= NULL
;
1167 g_hash_table_iter_init(&it
, priv
->users
);
1168 while (g_hash_table_iter_next(&it
, (gpointer
*)&name
, NULL
))
1169 names
= g_list_prepend(names
, name
);
1171 ops
->chat_remove_users(chat
, names
);
1175 g_hash_table_iter_init(&it
, priv
->users
);
1176 while (g_hash_table_iter_next(&it
, (gpointer
*)&name
, NULL
)) {
1177 purple_signal_emit(purple_conversations_get_handle(),
1178 "chat-user-leaving", chat
, name
, NULL
);
1179 purple_signal_emit(purple_conversations_get_handle(),
1180 "chat-user-left", chat
, name
, NULL
);
1183 g_hash_table_remove_all(priv
->users
);
1186 void purple_chat_conversation_set_nick(PurpleChatConversation
*chat
, const char *nick
) {
1187 PurpleChatConversationPrivate
*priv
= NULL
;
1189 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1191 priv
= purple_chat_conversation_get_instance_private(chat
);
1193 priv
->nick
= g_strdup(purple_normalize(
1194 purple_conversation_get_account(PURPLE_CONVERSATION(chat
)), nick
));
1196 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_NICK
]);
1199 const char *purple_chat_conversation_get_nick(PurpleChatConversation
*chat
) {
1200 PurpleChatConversationPrivate
*priv
= NULL
;
1202 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
1204 priv
= purple_chat_conversation_get_instance_private(chat
);
1209 invite_user_to_chat(gpointer data
, PurpleRequestFields
*fields
)
1211 PurpleConversation
*conv
;
1212 PurpleChatConversationPrivate
*priv
;
1213 const char *user
, *message
;
1216 priv
= purple_chat_conversation_get_instance_private(
1217 PURPLE_CHAT_CONVERSATION(conv
));
1218 user
= purple_request_fields_get_string(fields
, "screenname");
1219 message
= purple_request_fields_get_string(fields
, "message");
1221 purple_serv_chat_invite(purple_conversation_get_connection(conv
), priv
->id
, message
, user
);
1224 void purple_chat_conversation_invite_user(PurpleChatConversation
*chat
, const char *user
,
1225 const char *message
, gboolean confirm
)
1227 PurpleAccount
*account
;
1228 PurpleRequestFields
*fields
;
1229 PurpleRequestFieldGroup
*group
;
1230 PurpleRequestField
*field
;
1232 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1234 if (!user
|| !*user
|| !message
|| !*message
)
1237 account
= purple_conversation_get_account(PURPLE_CONVERSATION(chat
));
1240 purple_serv_chat_invite(purple_account_get_connection(account
),
1241 purple_chat_conversation_get_id(chat
), message
, user
);
1245 fields
= purple_request_fields_new();
1246 group
= purple_request_field_group_new(_("Invite to chat"));
1247 purple_request_fields_add_group(fields
, group
);
1249 field
= purple_request_field_string_new("screenname", _("Buddy"), user
, FALSE
);
1250 purple_request_field_group_add_field(group
, field
);
1251 purple_request_field_set_required(field
, TRUE
);
1252 purple_request_field_set_type_hint(field
, "screenname");
1254 field
= purple_request_field_string_new("message", _("Message"), message
, FALSE
);
1255 purple_request_field_group_add_field(group
, field
);
1257 purple_request_fields(chat
, _("Invite to chat"), NULL
,
1258 _("Please enter the name of the user you wish to invite, "
1259 "along with an optional invite message."),
1261 _("Invite"), G_CALLBACK(invite_user_to_chat
),
1263 purple_request_cpar_from_conversation(PURPLE_CONVERSATION(chat
)),
1268 purple_chat_conversation_has_user(PurpleChatConversation
*chat
, const char *user
)
1270 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), FALSE
);
1271 g_return_val_if_fail(user
!= NULL
, FALSE
);
1273 return (purple_chat_conversation_find_user(chat
, user
) != NULL
);
1277 purple_chat_conversation_leave(PurpleChatConversation
*chat
)
1279 PurpleChatConversationPrivate
*priv
= NULL
;
1281 g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
));
1283 priv
= purple_chat_conversation_get_instance_private(chat
);
1286 if (!g_object_get_data(G_OBJECT(chat
), "is-finalizing"))
1287 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_LEFT
]);
1289 purple_conversation_update(PURPLE_CONVERSATION(chat
), PURPLE_CONVERSATION_UPDATE_CHATLEFT
);
1293 purple_chat_conversation_has_left(PurpleChatConversation
*chat
)
1295 PurpleChatConversationPrivate
*priv
= NULL
;
1297 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), TRUE
);
1299 priv
= purple_chat_conversation_get_instance_private(chat
);
1304 chat_conversation_cleanup_for_rejoin(PurpleChatConversation
*chat
)
1307 PurpleAccount
*account
;
1308 PurpleConnection
*gc
;
1309 PurpleConversation
*conv
= PURPLE_CONVERSATION(chat
);
1310 PurpleChatConversationPrivate
*priv
=
1311 purple_chat_conversation_get_instance_private(chat
);
1313 account
= purple_conversation_get_account(conv
);
1315 purple_conversation_close_logs(conv
);
1316 purple_conversation_set_logging(conv
, TRUE
);
1318 gc
= purple_account_get_connection(account
);
1320 if ((disp
= purple_connection_get_display_name(gc
)) != NULL
)
1321 purple_chat_conversation_set_nick(chat
, disp
);
1324 purple_chat_conversation_set_nick(chat
,
1325 purple_account_get_username(account
));
1328 purple_chat_conversation_clear_users(chat
);
1329 purple_chat_conversation_set_topic(chat
, NULL
, NULL
);
1332 g_object_notify_by_pspec(G_OBJECT(chat
), chat_properties
[CHAT_PROP_LEFT
]);
1334 purple_conversation_update(conv
, PURPLE_CONVERSATION_UPDATE_CHATLEFT
);
1338 purple_chat_conversation_find_user(PurpleChatConversation
*chat
, const char *name
)
1340 PurpleChatConversationPrivate
*priv
= NULL
;
1342 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
1343 g_return_val_if_fail(name
!= NULL
, NULL
);
1345 priv
= purple_chat_conversation_get_instance_private(chat
);
1346 return g_hash_table_lookup(priv
->users
, name
);
1349 /**************************************************************************
1350 * GObject code for chats
1351 **************************************************************************/
1353 /* Set method for GObject properties */
1355 purple_chat_conversation_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
1358 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(obj
);
1362 purple_chat_conversation_set_id(chat
, g_value_get_int(value
));
1364 case CHAT_PROP_NICK
:
1365 purple_chat_conversation_set_nick(chat
, g_value_get_string(value
));
1367 case CHAT_PROP_LEFT
:
1369 gboolean left
= g_value_get_boolean(value
);
1371 purple_chat_conversation_leave(chat
);
1375 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1380 /* Get method for GObject properties */
1382 purple_chat_conversation_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
1385 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(obj
);
1388 case CHAT_PROP_TOPIC_WHO
:
1389 g_value_set_string(value
, purple_chat_conversation_get_topic_who(chat
));
1391 case CHAT_PROP_TOPIC
:
1392 g_value_set_string(value
, purple_chat_conversation_get_topic(chat
));
1395 g_value_set_int(value
, purple_chat_conversation_get_id(chat
));
1397 case CHAT_PROP_NICK
:
1398 g_value_set_string(value
, purple_chat_conversation_get_nick(chat
));
1400 case CHAT_PROP_LEFT
:
1401 g_value_set_boolean(value
, purple_chat_conversation_has_left(chat
));
1404 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1409 /* GObject initialization function */
1410 static void purple_chat_conversation_init(PurpleChatConversation
*chat
)
1412 PurpleChatConversationPrivate
*priv
=
1413 purple_chat_conversation_get_instance_private(chat
);
1415 priv
->users
= g_hash_table_new_full(_purple_conversation_user_hash
,
1416 _purple_conversation_user_equal
, g_free
, g_object_unref
);
1419 /* Called when done constructing */
1421 purple_chat_conversation_constructed(GObject
*object
)
1423 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(object
);
1424 PurpleAccount
*account
;
1427 G_OBJECT_CLASS(purple_chat_conversation_parent_class
)->
1428 constructed(object
);
1430 g_object_get(object
, "account", &account
, NULL
);
1432 if ((disp
= purple_connection_get_display_name(purple_account_get_connection(account
))))
1433 purple_chat_conversation_set_nick(chat
, disp
);
1435 purple_chat_conversation_set_nick(chat
,
1436 purple_account_get_username(account
));
1438 if (purple_prefs_get_bool("/purple/logging/log_chats"))
1439 purple_conversation_set_logging(PURPLE_CONVERSATION(chat
), TRUE
);
1441 g_object_unref(account
);
1444 /* GObject dispose function */
1446 purple_chat_conversation_dispose(GObject
*object
)
1448 PurpleChatConversationPrivate
*priv
=
1449 purple_chat_conversation_get_instance_private
1450 (PURPLE_CHAT_CONVERSATION(object
));
1452 g_hash_table_remove_all(priv
->users
);
1454 G_OBJECT_CLASS(purple_chat_conversation_parent_class
)->dispose(object
);
1457 /* GObject finalize function */
1459 purple_chat_conversation_finalize(GObject
*object
)
1461 PurpleChatConversation
*chat
= PURPLE_CHAT_CONVERSATION(object
);
1462 PurpleConnection
*gc
= purple_conversation_get_connection(PURPLE_CONVERSATION(chat
));
1463 PurpleChatConversationPrivate
*priv
=
1464 purple_chat_conversation_get_instance_private(chat
);
1468 /* Still connected */
1469 int chat_id
= purple_chat_conversation_get_id(chat
);
1472 * Close the window when the user tells us to, and let the protocol
1473 * deal with the internals on it's own time. Don't do this if the
1474 * protocol already knows it left the chat.
1476 if (!purple_chat_conversation_has_left(chat
))
1477 purple_serv_chat_leave(gc
, chat_id
);
1480 * If they didn't call purple_serv_got_chat_left by now, it's too late.
1481 * So we better do it for them before we destroy the thing.
1483 if (!purple_chat_conversation_has_left(chat
))
1484 purple_serv_got_chat_left(gc
, chat_id
);
1487 g_hash_table_destroy(priv
->users
);
1490 g_list_foreach(priv
->ignored
, (GFunc
)g_free
, NULL
);
1491 g_list_free(priv
->ignored
);
1492 priv
->ignored
= NULL
;
1495 g_free(priv
->topic
);
1502 G_OBJECT_CLASS(purple_chat_conversation_parent_class
)->finalize(object
);
1505 /* Class initializer function */
1506 static void purple_chat_conversation_class_init(PurpleChatConversationClass
*klass
)
1508 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
1509 PurpleConversationClass
*conv_class
= PURPLE_CONVERSATION_CLASS(klass
);
1511 obj_class
->dispose
= purple_chat_conversation_dispose
;
1512 obj_class
->finalize
= purple_chat_conversation_finalize
;
1513 obj_class
->constructed
= purple_chat_conversation_constructed
;
1515 /* Setup properties */
1516 obj_class
->get_property
= purple_chat_conversation_get_property
;
1517 obj_class
->set_property
= purple_chat_conversation_set_property
;
1519 conv_class
->write_message
= chat_conversation_write_message
;
1521 chat_properties
[CHAT_PROP_TOPIC_WHO
] = g_param_spec_string("topic-who",
1523 "Who set the chat topic.", NULL
,
1524 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
1526 chat_properties
[CHAT_PROP_TOPIC
] = g_param_spec_string("topic",
1528 "Topic of the chat.", NULL
,
1529 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
1531 chat_properties
[CHAT_PROP_ID
] = g_param_spec_int("chat-id",
1533 "The ID of the chat.", G_MININT
, G_MAXINT
, 0,
1534 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1536 chat_properties
[CHAT_PROP_NICK
] = g_param_spec_string("nick",
1538 "The nickname of the user in a chat.", NULL
,
1539 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1541 chat_properties
[CHAT_PROP_LEFT
] = g_param_spec_boolean("left",
1543 "Whether the user has left the chat.", FALSE
,
1544 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1546 g_object_class_install_properties(obj_class
, CHAT_PROP_LAST
,
1550 PurpleChatConversation
*
1551 purple_chat_conversation_new(PurpleAccount
*account
, const char *name
)
1553 PurpleChatConversation
*chat
;
1554 PurpleConnection
*gc
;
1556 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account
), NULL
);
1557 g_return_val_if_fail(name
!= NULL
, NULL
);
1559 /* Check if this conversation already exists. */
1560 if ((chat
= purple_conversations_find_chat_with_account(name
, account
)) != NULL
)
1562 if (!purple_chat_conversation_has_left(chat
)) {
1563 purple_debug_warning("conversationtypes", "Trying to create "
1564 "multiple chats (%s) with the same name is deprecated and "
1565 "will be removed in libpurple 3.0.0", name
);
1568 * This hack is necessary because some protocols (MSN) have unnamed chats
1569 * that all use the same name. A PurpleConversation for one of those
1570 * is only ever re-used if the user has left, so calls to
1571 * purple_conversation_new need to fall-through to creating a new
1573 * TODO 3.0.0: Remove this workaround and mandate unique names.
1576 chat_conversation_cleanup_for_rejoin(chat
);
1581 gc
= purple_account_get_connection(account
);
1582 g_return_val_if_fail(PURPLE_IS_CONNECTION(gc
), NULL
);
1584 chat
= g_object_new(PURPLE_TYPE_CHAT_CONVERSATION
,
1593 /**************************************************************************
1594 * Chat Conversation User API
1595 **************************************************************************/
1597 purple_chat_user_compare(PurpleChatUser
*a
, PurpleChatUser
*b
)
1599 PurpleChatUserFlags f1
= 0, f2
= 0;
1600 PurpleChatUserPrivate
*priva
, *privb
;
1601 char *user1
= NULL
, *user2
= NULL
;
1604 priva
= purple_chat_user_get_instance_private(a
);
1605 privb
= purple_chat_user_get_instance_private(b
);
1609 if (priva
->alias_key
)
1610 user1
= priva
->alias_key
;
1611 else if (priva
->name
)
1612 user1
= priva
->name
;
1617 if (privb
->alias_key
)
1618 user2
= privb
->alias_key
;
1619 else if (privb
->name
)
1620 user2
= privb
->name
;
1623 if (user1
== NULL
|| user2
== NULL
) {
1624 if (!(user1
== NULL
&& user2
== NULL
))
1625 ret
= (user1
== NULL
) ? -1: 1;
1626 } else if (f1
!= f2
) {
1627 /* sort more important users first */
1628 ret
= (f1
> f2
) ? -1 : 1;
1629 } else if (priva
->buddy
!= privb
->buddy
) {
1630 ret
= priva
->buddy
? -1 : 1;
1632 ret
= purple_utf8_strcasecmp(user1
, user2
);
1639 purple_chat_user_get_alias(PurpleChatUser
*cb
)
1641 PurpleChatUserPrivate
*priv
;
1643 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1645 priv
= purple_chat_user_get_instance_private(cb
);
1650 purple_chat_user_get_name(PurpleChatUser
*cb
)
1652 PurpleChatUserPrivate
*priv
;
1654 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1656 priv
= purple_chat_user_get_instance_private(cb
);
1661 purple_chat_user_set_flags(PurpleChatUser
*cb
,
1662 PurpleChatUserFlags flags
)
1664 PurpleConversationUiOps
*ops
;
1665 PurpleChatUserFlags oldflags
;
1666 PurpleChatUserPrivate
*priv
;
1668 g_return_if_fail(PURPLE_IS_CHAT_USER(cb
));
1670 priv
= purple_chat_user_get_instance_private(cb
);
1672 if (flags
== priv
->flags
)
1675 oldflags
= priv
->flags
;
1676 priv
->flags
= flags
;
1678 g_object_notify_by_pspec(G_OBJECT(cb
), cu_properties
[CU_PROP_FLAGS
]);
1680 ops
= purple_conversation_get_ui_ops(PURPLE_CONVERSATION(priv
->chat
));
1682 if (ops
!= NULL
&& ops
->chat_update_user
!= NULL
)
1683 ops
->chat_update_user(cb
);
1685 purple_signal_emit(purple_conversations_get_handle(),
1686 "chat-user-flags", cb
, oldflags
, flags
);
1690 purple_chat_user_get_flags(PurpleChatUser
*cb
)
1692 PurpleChatUserPrivate
*priv
;
1694 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), PURPLE_CHAT_USER_NONE
);
1696 priv
= purple_chat_user_get_instance_private(cb
);
1701 purple_chat_user_set_ui_data(PurpleChatUser
*cb
, gpointer ui_data
)
1703 g_return_if_fail(PURPLE_IS_CHAT_USER(cb
));
1705 cb
->ui_data
= ui_data
;
1709 purple_chat_user_get_ui_data(PurpleChatUser
*cb
)
1711 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1717 purple_chat_user_set_chat(PurpleChatUser
*cb
,
1718 PurpleChatConversation
*chat
)
1720 PurpleChatUserPrivate
*priv
;
1722 g_return_if_fail(PURPLE_IS_CHAT_USER(cb
));
1724 priv
= purple_chat_user_get_instance_private(cb
);
1727 g_object_notify_by_pspec(G_OBJECT(cb
), cu_properties
[CU_PROP_CHAT
]);
1730 PurpleChatConversation
*
1731 purple_chat_user_get_chat(PurpleChatUser
*cb
)
1733 PurpleChatUserPrivate
*priv
;
1735 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), NULL
);
1737 priv
= purple_chat_user_get_instance_private(cb
);
1742 purple_chat_user_is_buddy(PurpleChatUser
*cb
)
1744 PurpleChatUserPrivate
*priv
;
1746 g_return_val_if_fail(PURPLE_IS_CHAT_USER(cb
), FALSE
);
1748 priv
= purple_chat_user_get_instance_private(cb
);
1752 /**************************************************************************
1753 * GObject code for chat user
1754 **************************************************************************/
1756 /* Set method for GObject properties */
1758 purple_chat_user_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
1761 PurpleChatUser
*cb
= PURPLE_CHAT_USER(obj
);
1762 PurpleChatUserPrivate
*priv
=
1763 purple_chat_user_get_instance_private(cb
);
1767 priv
->chat
= g_value_get_object(value
);
1771 priv
->name
= g_value_dup_string(value
);
1774 g_free(priv
->alias
);
1775 priv
->alias
= g_value_dup_string(value
);
1778 priv
->flags
= g_value_get_flags(value
);
1781 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1786 /* Get method for GObject properties */
1788 purple_chat_user_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
1791 PurpleChatUser
*cb
= PURPLE_CHAT_USER(obj
);
1795 g_value_set_object(value
, purple_chat_user_get_chat(cb
));
1798 g_value_set_string(value
, purple_chat_user_get_name(cb
));
1801 g_value_set_string(value
, purple_chat_user_get_alias(cb
));
1804 g_value_set_flags(value
, purple_chat_user_get_flags(cb
));
1807 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1812 /* GObject initialization function */
1814 purple_chat_user_init(PurpleChatUser
*user
)
1818 /* Called when done constructing */
1820 purple_chat_user_constructed(GObject
*object
)
1822 PurpleChatUserPrivate
*priv
= purple_chat_user_get_instance_private(
1823 PURPLE_CHAT_USER(object
));
1824 PurpleAccount
*account
;
1826 G_OBJECT_CLASS(purple_chat_user_parent_class
)->constructed(object
);
1828 account
= purple_conversation_get_account(PURPLE_CONVERSATION(priv
->chat
));
1830 if (purple_blist_find_buddy(account
, priv
->name
) != NULL
)
1834 /* GObject finalize function */
1836 purple_chat_user_finalize(GObject
*object
)
1838 PurpleChatUser
*cb
= PURPLE_CHAT_USER(object
);
1839 PurpleChatUserPrivate
*priv
=
1840 purple_chat_user_get_instance_private(cb
);
1842 purple_signal_emit(purple_conversations_get_handle(),
1843 "deleting-chat-user", cb
);
1845 g_free(priv
->alias
);
1846 g_free(priv
->alias_key
);
1849 G_OBJECT_CLASS(purple_chat_user_parent_class
)->finalize(object
);
1852 /* Class initializer function */
1853 static void purple_chat_user_class_init(PurpleChatUserClass
*klass
)
1855 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
1857 obj_class
->constructed
= purple_chat_user_constructed
;
1858 obj_class
->finalize
= purple_chat_user_finalize
;
1860 /* Setup properties */
1861 obj_class
->get_property
= purple_chat_user_get_property
;
1862 obj_class
->set_property
= purple_chat_user_set_property
;
1864 cu_properties
[CU_PROP_CHAT
] = g_param_spec_object("chat", "Chat",
1865 "The chat the buddy belongs to.", PURPLE_TYPE_CHAT_CONVERSATION
,
1866 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
1867 G_PARAM_STATIC_STRINGS
);
1869 cu_properties
[CU_PROP_NAME
] = g_param_spec_string("name", "Name",
1870 "Name of the chat user.", NULL
,
1871 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
1873 cu_properties
[CU_PROP_ALIAS
] = g_param_spec_string("alias", "Alias",
1874 "Alias of the chat user.", NULL
,
1875 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
1877 cu_properties
[CU_PROP_FLAGS
] = g_param_spec_flags("flags", "Buddy flags",
1878 "The flags for the chat user.",
1879 PURPLE_TYPE_CHAT_USER_FLAGS
, PURPLE_CHAT_USER_NONE
,
1880 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
1882 g_object_class_install_properties(obj_class
, CU_PROP_LAST
, cu_properties
);
1886 purple_chat_user_new(PurpleChatConversation
*chat
, const char *name
,
1887 const char *alias
, PurpleChatUserFlags flags
)
1891 g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat
), NULL
);
1892 g_return_val_if_fail(name
!= NULL
, NULL
);
1894 cb
= g_object_new(PURPLE_TYPE_CHAT_USER
,