Modernizing PurpleChatConversation.
I wasn't able to do everything as PurpleConversation still isn't declared with
G_DECLARE_DERIVABLE_TYPE.
Testing Done:
Compiled ran locally with both xmpp mucs and irc channels.
Reviewed at https://reviews.imfreedom.org/r/583/
--- a/doc/reference/libpurple/libpurple-docs.xml Mon Apr 05 20:20:33 2021 -0500
+++ b/doc/reference/libpurple/libpurple-docs.xml Mon Apr 05 22:24:57 2021 -0500
@@ -47,7 +47,6 @@
<xi:include href="xml/contact.xml" />
<xi:include href="xml/connection.xml" />
<xi:include href="xml/conversation.xml" />
- <xi:include href="xml/conversationtypes.xml" />
<xi:include href="xml/conversations.xml" />
<xi:include href="xml/countingnode.xml" />
<xi:include href="xml/debug.xml" />
@@ -72,6 +71,7 @@
<xi:include href="xml/purpleaccountusersplit.xml" />
<xi:include href="xml/purpleattentiontype.xml" />
<xi:include href="xml/purplebuddypresence.xml" />
+ <xi:include href="xml/purplechatconversation.xml" /> <xi:include href="xml/purplechatuser.xml" />
<xi:include href="xml/purplecredentialmanager.xml" />
<xi:include href="xml/purplecredentialprovider.xml" />
--- a/libpurple/conversations.h Mon Apr 05 20:20:33 2021 -0500
+++ b/libpurple/conversations.h Mon Apr 05 22:24:57 2021 -0500
@@ -33,7 +33,7 @@
* @see_also: <link linkend="chapter-signals-conversation">Conversation signals</link>
-#include "conversationtypes.h"
+#include "purplechatconversation.h" --- a/libpurple/conversationtypes.c Mon Apr 05 20:20:33 2021 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1072 +0,0 @@
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#include <glib/gi18n-lib.h>
-#include "conversationtypes.h"
-#include "purpleprivate.h"
-/**************************************************************************/
-/* PurpleChatConversation */
-/**************************************************************************/
- * Data specific to Chats.
- GList *ignored; /* Ignored users. */
- char *who; /* The person who set the topic. */
- char *topic; /* The topic. */
- int id; /* The chat ID. */
- char *nick; /* Your nick in this chat. */
- gboolean left; /* We left the chat and kept the window open */
- GHashTable *users; /* Hash table of the users in the room. */
-} PurpleChatConversationPrivate;
-/* Chat Property enums */
-static GParamSpec *chat_properties[CHAT_PROP_LAST];
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleChatConversation, purple_chat_conversation,
- PURPLE_TYPE_CONVERSATION);
-/**************************************************************************
- * Chat Conversation API
- **************************************************************************/
-_purple_conversation_user_hash(gconstpointer data)
- const gchar *name = data;
- collated = g_utf8_collate_key(name, -1);
- hash = g_str_hash(collated);
-_purple_conversation_user_equal(gconstpointer a, gconstpointer b)
- return !g_utf8_collate(a, b);
-purple_chat_conversation_get_users(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- return g_hash_table_get_values(priv->users);
-purple_chat_conversation_get_users_count(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), 0);
- priv = purple_chat_conversation_get_instance_private(chat);
- return g_hash_table_size(priv->users);
-purple_chat_conversation_ignore(PurpleChatConversation *chat, const char *name)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- g_return_if_fail(name != NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- /* Make sure the user isn't already ignored. */
- if (purple_chat_conversation_is_ignored_user(chat, name))
- purple_chat_conversation_set_ignored(chat,
- g_list_append(priv->ignored, g_strdup(name)));
-purple_chat_conversation_unignore(PurpleChatConversation *chat, const char *name)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- g_return_if_fail(name != NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- /* Make sure the user is actually ignored. */
- if (!purple_chat_conversation_is_ignored_user(chat, name))
- item = g_list_find(purple_chat_conversation_get_ignored(chat),
- purple_chat_conversation_get_ignored_user(chat, name));
- purple_chat_conversation_set_ignored(chat,
- g_list_delete_link(priv->ignored, item));
-purple_chat_conversation_set_ignored(PurpleChatConversation *chat, GList *ignored)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- priv->ignored = ignored;
-purple_chat_conversation_get_ignored(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
-purple_chat_conversation_get_ignored_user(PurpleChatConversation *chat, const char *user)
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- g_return_val_if_fail(user != NULL, NULL);
- for (ignored = purple_chat_conversation_get_ignored(chat);
- ignored = ignored->next) {
- const char *ign = (const char *)ignored->data;
- if (!purple_utf8_strcasecmp(user, ign) ||
- ((*ign == '+' || *ign == '%') && !purple_utf8_strcasecmp(user, ign + 1)))
- if ((*ign == '+' && !purple_utf8_strcasecmp(user, ign + 1)) ||
- (*ign != '+' && !purple_utf8_strcasecmp(user, ign)))
-purple_chat_conversation_is_ignored_user(PurpleChatConversation *chat, const char *user)
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), FALSE);
- g_return_val_if_fail(user != NULL, FALSE);
- return (purple_chat_conversation_get_ignored_user(chat, user) != NULL);
-purple_chat_conversation_set_topic(PurpleChatConversation *chat, const char *who, const char *topic)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- priv = purple_chat_conversation_get_instance_private(chat);
- priv->who = g_strdup(who);
- priv->topic = g_strdup(topic);
- g_object_freeze_notify(obj);
- g_object_notify_by_pspec(obj, chat_properties[CHAT_PROP_TOPIC_WHO]);
- g_object_notify_by_pspec(obj, chat_properties[CHAT_PROP_TOPIC]);
- g_object_thaw_notify(obj);
- purple_conversation_update(PURPLE_CONVERSATION(chat),
- PURPLE_CONVERSATION_UPDATE_TOPIC);
- purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed",
- chat, priv->who, priv->topic);
-purple_chat_conversation_get_topic(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
-purple_chat_conversation_get_topic_who(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
-purple_chat_conversation_set_id(PurpleChatConversation *chat, int id)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- priv = purple_chat_conversation_get_instance_private(chat);
- g_object_notify_by_pspec(G_OBJECT(chat), chat_properties[CHAT_PROP_ID]);
-purple_chat_conversation_get_id(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), -1);
- priv = purple_chat_conversation_get_instance_private(chat);
-chat_conversation_write_message(PurpleConversation *conv, PurpleMessage *msg)
- PurpleChatConversationPrivate *priv = NULL;
- PurpleMessageFlags flags;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv));
- g_return_if_fail(msg != NULL);
- priv = purple_chat_conversation_get_instance_private(PURPLE_CHAT_CONVERSATION(conv));
- /* Don't display this if the person who wrote it is ignored. */
- if (purple_message_get_author(msg) && purple_chat_conversation_is_ignored_user(
- PURPLE_CHAT_CONVERSATION(conv), purple_message_get_author(msg)))
- flags = purple_message_get_flags(msg);
- if (flags & PURPLE_MESSAGE_RECV) {
- if (purple_utf8_has_word(purple_message_get_contents(msg), priv->nick)) {
- flags |= PURPLE_MESSAGE_NICK;
- purple_message_set_flags(msg, flags);
- _purple_conversation_write_common(conv, msg);
-purple_chat_conversation_add_user(PurpleChatConversation *chat, const char *user,
- const char *extra_msg, PurpleChatUserFlags flags,
- GList *users = g_list_append(NULL, (char *)user);
- GList *extra_msgs = g_list_append(NULL, (char *)extra_msg);
- GList *flags2 = g_list_append(NULL, GINT_TO_POINTER(flags));
- purple_chat_conversation_add_users(chat, users, extra_msgs, flags2, new_arrival);
- g_list_free(extra_msgs);
-purple_chat_conversation_add_users(PurpleChatConversation *chat, GList *users, GList *extra_msgs,
- GList *flags, gboolean new_arrivals)
- PurpleConversation *conv;
- PurpleConversationUiOps *ops;
- PurpleChatUser *chatuser;
- PurpleChatConversationPrivate *priv;
- PurpleAccount *account;
- PurpleProtocol *protocol;
- GList *cbuddies = NULL;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- g_return_if_fail(users != NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- conv = PURPLE_CONVERSATION(chat);
- ops = purple_conversation_get_ui_ops(conv);
- account = purple_conversation_get_account(conv);
- gc = purple_conversation_get_connection(conv);
- g_return_if_fail(PURPLE_IS_CONNECTION(gc));
- protocol = purple_connection_get_protocol(gc);
- g_return_if_fail(PURPLE_IS_PROTOCOL(protocol));
- while ((ul != NULL) && (fl != NULL)) {
- const char *user = (const char *)ul->data;
- const char *alias = user;
- PurpleChatUserFlags flag = GPOINTER_TO_INT(fl->data);
- const char *extra_msg = (extra_msgs ? extra_msgs->data : NULL);
- if(!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) {
- if (purple_strequal(priv->nick, purple_normalize(account, user))) {
- const char *alias2 = purple_account_get_private_alias(account);
- const char *display_name = purple_connection_get_display_name(gc);
- if (display_name != NULL)
- if ((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), user)) != NULL)
- alias = purple_buddy_get_contact_alias(buddy);
- quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
- "chat-user-joining", chat, user, flag)) ||
- purple_chat_conversation_is_ignored_user(chat, user);
- chatuser = purple_chat_user_new(chat, user, alias, flag);
- g_hash_table_replace(priv->users,
- g_strdup(purple_chat_user_get_name(chatuser)),
- cbuddies = g_list_prepend(cbuddies, chatuser);
- if (!quiet && new_arrivals) {
- char *alias_esc = g_markup_escape_text(alias, -1);
- tmp = g_strdup_printf(_("%s entered the room."), alias_esc);
- char *extra_msg_esc = g_markup_escape_text(extra_msg, -1);
- tmp = g_strdup_printf(_("%s [<I>%s</I>] entered the room."),
- alias_esc, extra_msg_esc);
- purple_conversation_write_system_message(
- conv, tmp, PURPLE_MESSAGE_NO_LINKIFY);
- purple_signal_emit(purple_conversations_get_handle(),
- "chat-user-joined", chat, user, flag, new_arrivals);
- if (extra_msgs != NULL)
- extra_msgs = extra_msgs->next;
- cbuddies = g_list_sort(cbuddies, (GCompareFunc)purple_chat_user_compare);
- if (ops != NULL && ops->chat_add_users != NULL)
- ops->chat_add_users(chat, cbuddies, new_arrivals);
-purple_chat_conversation_rename_user(PurpleChatConversation *chat, const char *old_user,
- PurpleConversation *conv;
- PurpleConversationUiOps *ops;
- PurpleAccount *account;
- PurpleProtocol *protocol;
- PurpleChatUserFlags flags;
- PurpleChatConversationPrivate *priv;
- const char *new_alias = new_user;
- gboolean is_me = FALSE;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- g_return_if_fail(old_user != NULL);
- g_return_if_fail(new_user != NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- conv = PURPLE_CONVERSATION(chat);
- ops = purple_conversation_get_ui_ops(conv);
- account = purple_conversation_get_account(conv);
- gc = purple_conversation_get_connection(conv);
- g_return_if_fail(PURPLE_IS_CONNECTION(gc));
- protocol = purple_connection_get_protocol(gc);
- g_return_if_fail(PURPLE_IS_PROTOCOL(protocol));
- if (purple_strequal(priv->nick, purple_normalize(account, old_user))) {
- /* Note this for later. */
- if(!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) {
- alias = purple_account_get_private_alias(account);
- const char *display_name = purple_connection_get_display_name(gc);
- if (display_name != NULL)
- new_alias = display_name;
- } else if (!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) {
- if ((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), new_user)) != NULL)
- new_alias = purple_buddy_get_contact_alias(buddy);
- flags = purple_chat_user_get_flags(purple_chat_conversation_find_user(chat, old_user));
- cb = purple_chat_user_new(chat, new_user, new_alias, flags);
- g_hash_table_replace(priv->users,
- g_strdup(purple_chat_user_get_name(cb)), cb);
- if (ops != NULL && ops->chat_rename_user != NULL)
- ops->chat_rename_user(chat, old_user, new_user, new_alias);
- cb = purple_chat_conversation_find_user(chat, old_user);
- g_hash_table_remove(priv->users, purple_chat_user_get_name(cb));
- if (purple_chat_conversation_is_ignored_user(chat, old_user)) {
- purple_chat_conversation_unignore(chat, old_user);
- purple_chat_conversation_ignore(chat, new_user);
- else if (purple_chat_conversation_is_ignored_user(chat, new_user))
- purple_chat_conversation_unignore(chat, new_user);
- purple_chat_conversation_set_nick(chat, new_user);
- if (purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") &&
- !purple_chat_conversation_is_ignored_user(chat, new_user)) {
- char *escaped = g_markup_escape_text(new_user, -1);
- g_snprintf(tmp, sizeof(tmp),
- _("You are now known as %s"), escaped);
- const char *old_alias = old_user;
- const char *new_alias = new_user;
- if (!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) {
- if ((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), old_user)) != NULL)
- old_alias = purple_buddy_get_contact_alias(buddy);
- if ((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), new_user)) != NULL)
- new_alias = purple_buddy_get_contact_alias(buddy);
- escaped = g_markup_escape_text(old_alias, -1);
- escaped2 = g_markup_escape_text(new_alias, -1);
- g_snprintf(tmp, sizeof(tmp),
- _("%s is now known as %s"), escaped, escaped2);
- purple_conversation_write_system_message(conv,
- tmp, PURPLE_MESSAGE_NO_LINKIFY);
-purple_chat_conversation_remove_user(PurpleChatConversation *chat, const char *user, const char *reason)
- GList *users = g_list_append(NULL, (char *)user);
- purple_chat_conversation_remove_users(chat, users, reason);
-purple_chat_conversation_remove_users(PurpleChatConversation *chat, GList *users, const char *reason)
- PurpleConversation *conv;
- PurpleProtocol *protocol;
- PurpleConversationUiOps *ops;
- PurpleChatConversationPrivate *priv;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- g_return_if_fail(users != NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- conv = PURPLE_CONVERSATION(chat);
- gc = purple_conversation_get_connection(conv);
- g_return_if_fail(PURPLE_IS_CONNECTION(gc));
- protocol = purple_connection_get_protocol(gc);
- g_return_if_fail(PURPLE_IS_PROTOCOL(protocol));
- ops = purple_conversation_get_ui_ops(conv);
- for (l = users; l != NULL; l = l->next) {
- const char *user = (const char *)l->data;
- quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(purple_conversations_get_handle(),
- "chat-user-leaving", chat, user, reason)) |
- purple_chat_conversation_is_ignored_user(chat, user);
- cb = purple_chat_conversation_find_user(chat, user);
- g_hash_table_remove(priv->users,
- purple_chat_user_get_name(cb));
- /* NOTE: Don't remove them from ignored in case they re-enter. */
- const char *alias = user;
- if (!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) {
- if ((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), user)) != NULL)
- alias = purple_buddy_get_contact_alias(buddy);
- alias_esc = g_markup_escape_text(alias, -1);
- if (reason == NULL || !*reason)
- tmp = g_strdup_printf(_("%s left the room."), alias_esc);
- char *reason_esc = g_markup_escape_text(reason, -1);
- tmp = g_strdup_printf(_("%s left the room (%s)."),
- alias_esc, reason_esc);
- purple_conversation_write_system_message(conv,
- tmp, PURPLE_MESSAGE_NO_LINKIFY);
- purple_signal_emit(purple_conversations_get_handle(), "chat-user-left",
- if (ops != NULL && ops->chat_remove_users != NULL)
- ops->chat_remove_users(chat, users);
-purple_chat_conversation_clear_users(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- PurpleConversationUiOps *ops;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- priv = purple_chat_conversation_get_instance_private(chat);
- ops = purple_conversation_get_ui_ops(PURPLE_CONVERSATION(chat));
- if (ops != NULL && ops->chat_remove_users != NULL) {
- g_hash_table_iter_init(&it, priv->users);
- while (g_hash_table_iter_next(&it, (gpointer*)&name, NULL))
- names = g_list_prepend(names, name);
- ops->chat_remove_users(chat, names);
- g_hash_table_iter_init(&it, priv->users);
- while (g_hash_table_iter_next(&it, (gpointer*)&name, NULL)) {
- purple_signal_emit(purple_conversations_get_handle(),
- "chat-user-leaving", chat, name, NULL);
- purple_signal_emit(purple_conversations_get_handle(),
- "chat-user-left", chat, name, NULL);
- g_hash_table_remove_all(priv->users);
-void purple_chat_conversation_set_nick(PurpleChatConversation *chat, const char *nick) {
- PurpleChatConversationPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- priv = purple_chat_conversation_get_instance_private(chat);
- priv->nick = g_strdup(purple_normalize(
- purple_conversation_get_account(PURPLE_CONVERSATION(chat)), nick));
- g_object_notify_by_pspec(G_OBJECT(chat), chat_properties[CHAT_PROP_NICK]);
-const char *purple_chat_conversation_get_nick(PurpleChatConversation *chat) {
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
-invite_user_to_chat(gpointer data, PurpleRequestFields *fields)
- PurpleConversation *conv;
- PurpleChatConversationPrivate *priv;
- const char *user, *message;
- priv = purple_chat_conversation_get_instance_private(
- PURPLE_CHAT_CONVERSATION(conv));
- user = purple_request_fields_get_string(fields, "screenname");
- message = purple_request_fields_get_string(fields, "message");
- purple_serv_chat_invite(purple_conversation_get_connection(conv), priv->id, message, user);
-void purple_chat_conversation_invite_user(PurpleChatConversation *chat, const char *user,
- const char *message, gboolean confirm)
- PurpleAccount *account;
- PurpleRequestFields *fields;
- PurpleRequestFieldGroup *group;
- PurpleRequestField *field;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- if (!user || !*user || !message || !*message)
- account = purple_conversation_get_account(PURPLE_CONVERSATION(chat));
- purple_serv_chat_invite(purple_account_get_connection(account),
- purple_chat_conversation_get_id(chat), message, user);
- fields = purple_request_fields_new();
- group = purple_request_field_group_new(_("Invite to chat"));
- purple_request_fields_add_group(fields, group);
- field = purple_request_field_string_new("screenname", _("Buddy"), user, FALSE);
- purple_request_field_group_add_field(group, field);
- purple_request_field_set_required(field, TRUE);
- purple_request_field_set_type_hint(field, "screenname");
- field = purple_request_field_string_new("message", _("Message"), message, FALSE);
- purple_request_field_group_add_field(group, field);
- purple_request_fields(chat, _("Invite to chat"), NULL,
- _("Please enter the name of the user you wish to invite, "
- "along with an optional invite message."),
- _("Invite"), G_CALLBACK(invite_user_to_chat),
- purple_request_cpar_from_conversation(PURPLE_CONVERSATION(chat)),
-purple_chat_conversation_has_user(PurpleChatConversation *chat, const char *user)
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), FALSE);
- g_return_val_if_fail(user != NULL, FALSE);
- return (purple_chat_conversation_find_user(chat, user) != NULL);
-purple_chat_conversation_leave(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat));
- priv = purple_chat_conversation_get_instance_private(chat);
- if (!g_object_get_data(G_OBJECT(chat), "is-finalizing"))
- g_object_notify_by_pspec(G_OBJECT(chat), chat_properties[CHAT_PROP_LEFT]);
- purple_conversation_update(PURPLE_CONVERSATION(chat), PURPLE_CONVERSATION_UPDATE_CHATLEFT);
-purple_chat_conversation_has_left(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), TRUE);
- priv = purple_chat_conversation_get_instance_private(chat);
-chat_conversation_cleanup_for_rejoin(PurpleChatConversation *chat)
- PurpleAccount *account;
- PurpleConversation *conv = PURPLE_CONVERSATION(chat);
- PurpleChatConversationPrivate *priv =
- purple_chat_conversation_get_instance_private(chat);
- account = purple_conversation_get_account(conv);
- purple_conversation_close_logs(conv);
- purple_conversation_set_logging(conv, TRUE);
- gc = purple_account_get_connection(account);
- if ((disp = purple_connection_get_display_name(gc)) != NULL)
- purple_chat_conversation_set_nick(chat, disp);
- purple_chat_conversation_set_nick(chat,
- purple_account_get_username(account));
- purple_chat_conversation_clear_users(chat);
- purple_chat_conversation_set_topic(chat, NULL, NULL);
- g_object_notify_by_pspec(G_OBJECT(chat), chat_properties[CHAT_PROP_LEFT]);
- purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_CHATLEFT);
-purple_chat_conversation_find_user(PurpleChatConversation *chat, const char *name)
- PurpleChatConversationPrivate *priv = NULL;
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL);
- g_return_val_if_fail(name != NULL, NULL);
- priv = purple_chat_conversation_get_instance_private(chat);
- return g_hash_table_lookup(priv->users, name);
-/**************************************************************************
- * GObject code for chats
- **************************************************************************/
-/* Set method for GObject properties */
-purple_chat_conversation_set_property(GObject *obj, guint param_id, const GValue *value,
- PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(obj);
- purple_chat_conversation_set_id(chat, g_value_get_int(value));
- purple_chat_conversation_set_nick(chat, g_value_get_string(value));
- gboolean left = g_value_get_boolean(value);
- purple_chat_conversation_leave(chat);
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-/* Get method for GObject properties */
-purple_chat_conversation_get_property(GObject *obj, guint param_id, GValue *value,
- PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(obj);
- case CHAT_PROP_TOPIC_WHO:
- g_value_set_string(value, purple_chat_conversation_get_topic_who(chat));
- g_value_set_string(value, purple_chat_conversation_get_topic(chat));
- g_value_set_int(value, purple_chat_conversation_get_id(chat));
- g_value_set_string(value, purple_chat_conversation_get_nick(chat));
- g_value_set_boolean(value, purple_chat_conversation_has_left(chat));
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-/* GObject initialization function */
-static void purple_chat_conversation_init(PurpleChatConversation *chat)
- PurpleChatConversationPrivate *priv =
- purple_chat_conversation_get_instance_private(chat);
- priv->users = g_hash_table_new_full(_purple_conversation_user_hash,
- _purple_conversation_user_equal, g_free, g_object_unref);
-/* Called when done constructing */
-purple_chat_conversation_constructed(GObject *object)
- PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(object);
- PurpleAccount *account;
- G_OBJECT_CLASS(purple_chat_conversation_parent_class)->
- g_object_get(object, "account", &account, NULL);
- if ((disp = purple_connection_get_display_name(purple_account_get_connection(account))))
- purple_chat_conversation_set_nick(chat, disp);
- purple_chat_conversation_set_nick(chat,
- purple_account_get_username(account));
- if (purple_prefs_get_bool("/purple/logging/log_chats"))
- purple_conversation_set_logging(PURPLE_CONVERSATION(chat), TRUE);
- g_object_unref(account);
-/* GObject dispose function */
-purple_chat_conversation_dispose(GObject *object)
- PurpleChatConversationPrivate *priv =
- purple_chat_conversation_get_instance_private
- (PURPLE_CHAT_CONVERSATION(object));
- g_hash_table_remove_all(priv->users);
- G_OBJECT_CLASS(purple_chat_conversation_parent_class)->dispose(object);
-/* GObject finalize function */
-purple_chat_conversation_finalize(GObject *object)
- PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(object);
- PurpleConnection *gc = purple_conversation_get_connection(PURPLE_CONVERSATION(chat));
- PurpleChatConversationPrivate *priv =
- purple_chat_conversation_get_instance_private(chat);
- int chat_id = purple_chat_conversation_get_id(chat);
- * Close the window when the user tells us to, and let the protocol
- * deal with the internals on it's own time. Don't do this if the
- * protocol already knows it left the chat.
- if (!purple_chat_conversation_has_left(chat))
- purple_serv_chat_leave(gc, chat_id);
- * If they didn't call purple_serv_got_chat_left by now, it's too late.
- * So we better do it for them before we destroy the thing.
- if (!purple_chat_conversation_has_left(chat))
- purple_serv_got_chat_left(gc, chat_id);
- g_hash_table_destroy(priv->users);
- g_list_free_full(priv->ignored, g_free);
- G_OBJECT_CLASS(purple_chat_conversation_parent_class)->finalize(object);
-/* Class initializer function */
-static void purple_chat_conversation_class_init(PurpleChatConversationClass *klass)
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
- PurpleConversationClass *conv_class = PURPLE_CONVERSATION_CLASS(klass);
- obj_class->dispose = purple_chat_conversation_dispose;
- obj_class->finalize = purple_chat_conversation_finalize;
- obj_class->constructed = purple_chat_conversation_constructed;
- obj_class->get_property = purple_chat_conversation_get_property;
- obj_class->set_property = purple_chat_conversation_set_property;
- conv_class->write_message = chat_conversation_write_message;
- chat_properties[CHAT_PROP_TOPIC_WHO] = g_param_spec_string("topic-who",
- "Who set the chat topic.", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- chat_properties[CHAT_PROP_TOPIC] = g_param_spec_string("topic",
- "Topic of the chat.", NULL,
- G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
- chat_properties[CHAT_PROP_ID] = g_param_spec_int("chat-id",
- "The ID of the chat.", G_MININT, G_MAXINT, 0,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- chat_properties[CHAT_PROP_NICK] = g_param_spec_string("nick",
- "The nickname of the user in a chat.", NULL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- chat_properties[CHAT_PROP_LEFT] = g_param_spec_boolean("left",
- "Whether the user has left the chat.", FALSE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
- g_object_class_install_properties(obj_class, CHAT_PROP_LAST,
-PurpleChatConversation *
-purple_chat_conversation_new(PurpleAccount *account, const char *name)
- PurpleChatConversation *chat;
- g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
- g_return_val_if_fail(name != NULL, NULL);
- /* Check if this conversation already exists. */
- if ((chat = purple_conversations_find_chat_with_account(name, account)) != NULL)
- if (!purple_chat_conversation_has_left(chat)) {
- purple_debug_warning("conversationtypes", "Trying to create "
- "multiple chats (%s) with the same name is deprecated and "
- "will be removed in libpurple 3.0.0", name);
- * This hack is necessary because some protocols (MSN) have unnamed chats
- * that all use the same name. A PurpleConversation for one of those
- * is only ever re-used if the user has left, so calls to
- * purple_conversation_new need to fall-through to creating a new
- * TODO 3.0.0: Remove this workaround and mandate unique names.
- chat_conversation_cleanup_for_rejoin(chat);
- gc = purple_account_get_connection(account);
- g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL);
- chat = g_object_new(PURPLE_TYPE_CHAT_CONVERSATION,
--- a/libpurple/conversationtypes.h Mon Apr 05 20:20:33 2021 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,414 +0,0 @@
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
-# error "only <purple.h> may be included directly"
-#ifndef PURPLE_CONVERSATION_TYPES_H
-#define PURPLE_CONVERSATION_TYPES_H
- * SECTION:conversationtypes
- * @section_id: libpurple-conversationtypes
- * @short_description: <filename>conversationtypes.h</filename>
- * @title: Chat Conversation Objects
-/**************************************************************************/
-/**************************************************************************/
-#define PURPLE_TYPE_CHAT_CONVERSATION (purple_chat_conversation_get_type())
-#define PURPLE_CHAT_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversation))
-#define PURPLE_CHAT_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversationClass))
-#define PURPLE_IS_CHAT_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_CHAT_CONVERSATION))
-#define PURPLE_IS_CHAT_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CHAT_CONVERSATION))
-#define PURPLE_CHAT_CONVERSATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversationClass))
-typedef struct _PurpleChatConversation PurpleChatConversation;
-typedef struct _PurpleChatConversationClass PurpleChatConversationClass;
-#include "purplechatuser.h"
-#include "purpleimconversation.h"
-#include "conversation.h"
-/**************************************************************************/
-/* PurpleChatConversation */
-/**************************************************************************/
- * PurpleChatConversation:
- * Structure representing a chat conversation instance.
-struct _PurpleChatConversation
- PurpleConversation parent_object;
- * PurpleChatConversationClass:
- * Base class for all #PurpleChatConversation's
-struct _PurpleChatConversationClass {
- PurpleConversationClass parent_class;
- void (*_purple_reserved1)(void);
- void (*_purple_reserved2)(void);
- void (*_purple_reserved3)(void);
- void (*_purple_reserved4)(void);
-/**************************************************************************/
-/* Chat Conversation API */
-/**************************************************************************/
- * purple_chat_conversation_get_type:
- * Returns: The #GType for the ChatConversation object.
-GType purple_chat_conversation_get_type(void);
- * purple_chat_conversation_new:
- * @account: The account opening the conversation window on the purple
- * @name: The name of the conversation.
- * Creates a new chat conversation.
- * Returns: The new conversation.
-PurpleChatConversation *purple_chat_conversation_new(PurpleAccount *account,
- * purple_chat_conversation_get_users:
- * Returns a list of users in the chat room. The members of the list
- * are PurpleChatUser objects.
- * Returns: (element-type PurpleChatUser) (transfer container):
- * The list of users. Use g_list_free() when done
-GList *purple_chat_conversation_get_users(PurpleChatConversation *chat);
- * purple_chat_conversation_get_users_count:
- * Returns count of users in the chat room.
- * Returns: The count of users in the chat room.
-purple_chat_conversation_get_users_count(PurpleChatConversation *chat);
- * purple_chat_conversation_ignore:
- * @name: The name of the user.
- * Ignores a user in a chat room.
-void purple_chat_conversation_ignore(PurpleChatConversation *chat, const char *name);
- * purple_chat_conversation_unignore:
- * @name: The name of the user.
- * Unignores a user in a chat room.
-void purple_chat_conversation_unignore(PurpleChatConversation *chat, const char *name);
- * purple_chat_conversation_set_ignored:
- * @ignored: (element-type utf8): The list of ignored users.
- * Sets the list of ignored users in the chat room.
- * Returns: (element-type utf8) (transfer none): The list passed.
-GList *purple_chat_conversation_set_ignored(PurpleChatConversation *chat, GList *ignored);
- * purple_chat_conversation_get_ignored:
- * Returns the list of ignored users in the chat room.
- * Returns: (element-type utf8) (transfer none): The list of ignored users.
-GList *purple_chat_conversation_get_ignored(PurpleChatConversation *chat);
- * purple_chat_conversation_get_ignored_user:
- * @user: The user to check in the ignore list.
- * Returns the actual name of the specified ignored user, if it exists in
- * If the user found contains a prefix, such as '+' or '\@', this is also
- * returned. The username passed to the function does not have to have this
- * Returns: The ignored user if found, complete with prefixes, or %NULL
-const char *purple_chat_conversation_get_ignored_user(PurpleChatConversation *chat,
- * purple_chat_conversation_is_ignored_user:
- * Returns %TRUE if the specified user is ignored.
- * Returns: %TRUE if the user is in the ignore list; %FALSE otherwise.
-gboolean purple_chat_conversation_is_ignored_user(PurpleChatConversation *chat,
- * purple_chat_conversation_set_topic:
- * @who: The user that set the topic.
- * Sets the chat room's topic.
-void purple_chat_conversation_set_topic(PurpleChatConversation *chat, const char *who,
- * purple_chat_conversation_get_topic:
- * Returns the chat room's topic.
- * Returns: The chat's topic.
-const char *purple_chat_conversation_get_topic(PurpleChatConversation *chat);
- * purple_chat_conversation_get_topic_who:
- * Returns who set the chat room's topic.
- * Returns: Who set the topic.
-const char *purple_chat_conversation_get_topic_who(PurpleChatConversation *chat);
- * purple_chat_conversation_set_id:
- * Sets the chat room's ID.
-void purple_chat_conversation_set_id(PurpleChatConversation *chat, int id);
- * purple_chat_conversation_get_id:
- * Returns the chat room's ID.
-int purple_chat_conversation_get_id(PurpleChatConversation *chat);
- * purple_chat_conversation_add_user:
- * @user: The user to add.
- * @extra_msg: An extra message to display with the join message.
- * @flags: The users flags
- * @new_arrival: Decides whether or not to show a join notice.
- * Adds a user to a chat.
-void purple_chat_conversation_add_user(PurpleChatConversation *chat, const char *user,
- const char *extra_msg, PurpleChatUserFlags flags,
- * purple_chat_conversation_add_users:
- * @users: (element-type utf8): The list of users to add.
- * @extra_msgs: (element-type utf8) (nullable): An extra message to display
- * with the join message for each user. This list may be shorter
- * than @users, in which case, the users after the end of
- * extra_msgs will not have an extra message. By extension, this
- * means that extra_msgs can simply be %NULL and none of the users
- * will have an extra message.
- * @flags: (element-type PurpleChatUserFlags): The list of flags for each user.
- * This list data should be an int converted to pointer using
- * GINT_TO_POINTER(flag)
- * @new_arrivals: Decides whether or not to show join notices.
- * Adds a list of users to a chat.
- * The data is copied from @users, @extra_msgs, and @flags, so it is up to
- * the caller to free this list after calling this function.
-void purple_chat_conversation_add_users(PurpleChatConversation *chat,
- GList *users, GList *extra_msgs, GList *flags, gboolean new_arrivals);
- * purple_chat_conversation_rename_user:
- * @old_user: The old username.
- * @new_user: The new username.
- * Renames a user in a chat.
-void purple_chat_conversation_rename_user(PurpleChatConversation *chat,
- const char *old_user, const char *new_user);
- * purple_chat_conversation_remove_user:
- * @user: The user that is being removed.
- * @reason: The optional reason given for the removal. Can be %NULL.
- * Removes a user from a chat, optionally with a reason.
- * It is up to the developer to free this list after calling this function.
-void purple_chat_conversation_remove_user(PurpleChatConversation *chat,
- const char *user, const char *reason);
- * purple_chat_conversation_remove_users:
- * @users: (element-type utf8): The users that are being removed.
- * @reason: The optional reason given for the removal. Can be %NULL.
- * Removes a list of users from a chat, optionally with a single reason.
-void purple_chat_conversation_remove_users(PurpleChatConversation *chat,
- GList *users, const char *reason);
- * purple_chat_conversation_has_user:
- * @user: The user to look for.
- * Checks if a user is in a chat
- * Returns: TRUE if the user is in the chat, FALSE if not
-gboolean purple_chat_conversation_has_user(PurpleChatConversation *chat,
- * purple_chat_conversation_clear_users:
- * Clears all users from a chat.
-void purple_chat_conversation_clear_users(PurpleChatConversation *chat);
- * purple_chat_conversation_set_nick:
- * Sets your nickname (used for hilighting) for a chat.
-void purple_chat_conversation_set_nick(PurpleChatConversation *chat,
- * purple_chat_conversation_get_nick:
- * Gets your nickname (used for hilighting) for a chat.
-const char *purple_chat_conversation_get_nick(PurpleChatConversation *chat);
- * purple_chat_conversation_leave:
- * Lets the core know we left a chat, without destroying it.
- * Called from purple_serv_got_chat_left().
-void purple_chat_conversation_leave(PurpleChatConversation *chat);
- * purple_chat_conversation_find_user:
- * @name: The name of the chat user to find.
- * Find a chat user in a chat
- * Returns: (transfer none):
- * The @PurpleChatUser with the name refered by @name.
-PurpleChatUser *purple_chat_conversation_find_user(PurpleChatConversation *chat,
- * purple_chat_conversation_invite_user:
- * @user: The user to invite to the chat.
- * @message: The message to send with the invitation.
- * @confirm: Prompt before sending the invitation. The user is always
- * prompted if either \a user or \a message is %NULL.
- * Invite a user to a chat.
- * The user will be prompted to enter the user's name or a message if one is
-void purple_chat_conversation_invite_user(PurpleChatConversation *chat,
- const char *user, const char *message, gboolean confirm);
- * purple_chat_conversation_has_left:
- * Returns true if we're no longer in this chat,
- * and just left the window open.
- * Returns: %TRUE if we left the chat already, %FALSE if
-gboolean purple_chat_conversation_has_left(PurpleChatConversation *chat);
-#endif /* PURPLE_CONVERSATION_TYPES_H */
--- a/libpurple/meson.build Mon Apr 05 20:20:33 2021 -0500
+++ b/libpurple/meson.build Mon Apr 05 22:24:57 2021 -0500
@@ -12,7 +12,6 @@
@@ -49,6 +48,7 @@
+ 'purplechatconversation.c', 'purplecredentialmanager.c',
'purplecredentialprovider.c',
@@ -110,7 +110,6 @@
@@ -140,6 +139,7 @@
'purpleaccountusersplit.h',
+ 'purplechatconversation.h', 'purplecredentialmanager.h',
'purplecredentialprovider.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplechatconversation.c Mon Apr 05 22:24:57 2021 -0500
@@ -0,0 +1,1088 @@
+ * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +#include <glib/gi18n-lib.h> +#include "purplechatconversation.h" +#include "purpleprivate.h" + GList *ignored; /* Ignored users. */ + char *who; /* The person who set the topic. */ + char *topic; /* The topic. */ + int id; /* The chat ID. */ + char *nick; /* Your nick in this chat. */ + gboolean left; /* We left the chat and kept the window open */ + GHashTable *users; /* Hash table of the users in the room. */ +} PurpleChatConversationPrivate; +/* Chat Property enums */ +static GParamSpec *properties[N_PROPERTIES] = { NULL, }; +G_DEFINE_TYPE_WITH_PRIVATE(PurpleChatConversation, purple_chat_conversation, + PURPLE_TYPE_CONVERSATION); +/************************************************************************** + **************************************************************************/ +purple_conversation_user_hash(gconstpointer data) { + collated = g_utf8_collate_key((const gchar *)data, -1); + hash = g_str_hash(collated); +purple_conversation_user_equal(gconstpointer a, gconstpointer b) { + return !g_utf8_collate(a, b); +purple_chat_conversation_clear_users_helper(gpointer data, gpointer user_data) + PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(user_data); + const gchar *name = (const gchar *)data; + gpointer handle = purple_conversations_get_handle(); + purple_signal_emit(handle, "chat-user-leaving", chat, name, NULL); + purple_signal_emit(handle, "chat-user-left", chat, name, NULL); +/****************************************************************************** + * PurpleConversation Implementation + *****************************************************************************/ +chat_conversation_write_message(PurpleConversation *conv, PurpleMessage *msg) { + PurpleChatConversation *chat_conv = PURPLE_CHAT_CONVERSATION(conv); + PurpleChatConversationPrivate *priv = NULL; + PurpleMessageFlags flags; + const gchar *author = NULL; + g_return_if_fail(msg != NULL); + priv = purple_chat_conversation_get_instance_private(chat_conv); + /* Don't display this if the person who wrote it is ignored. */ + author = purple_message_get_author(msg); + if(purple_chat_conversation_is_ignored_user(chat_conv, author)) { + flags = purple_message_get_flags(msg); + if(flags & PURPLE_MESSAGE_RECV) { + if(purple_utf8_has_word(purple_message_get_contents(msg), priv->nick)) { + flags |= PURPLE_MESSAGE_NICK; + purple_message_set_flags(msg, flags); + _purple_conversation_write_common(conv, msg); +/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +purple_chat_conversation_set_property(GObject *obj, guint param_id, + const GValue *value, GParamSpec *pspec) + PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(obj); + purple_chat_conversation_set_id(chat, g_value_get_int(value)); + purple_chat_conversation_set_nick(chat, g_value_get_string(value)); + if(g_value_get_boolean(value)) { + purple_chat_conversation_leave(chat); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +purple_chat_conversation_get_property(GObject *obj, guint param_id, + GValue *value, GParamSpec *pspec) + PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(obj); + g_value_set_string(value, purple_chat_conversation_get_topic_who(chat)); + g_value_set_string(value, purple_chat_conversation_get_topic(chat)); + g_value_set_int(value, purple_chat_conversation_get_id(chat)); + g_value_set_string(value, purple_chat_conversation_get_nick(chat)); + g_value_set_boolean(value, purple_chat_conversation_has_left(chat)); + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); +purple_chat_conversation_init(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + priv = purple_chat_conversation_get_instance_private(chat); + priv->users = g_hash_table_new_full(purple_conversation_user_hash, + purple_conversation_user_equal, + g_free, g_object_unref); +purple_chat_conversation_constructed(GObject *obj) { + PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(obj); + PurpleAccount *account = NULL; + PurpleConnection *connection = NULL; + const gchar *display_name = NULL; + G_OBJECT_CLASS(purple_chat_conversation_parent_class)->constructed(obj); + g_object_get(obj, "account", &account, NULL); + connection = purple_account_get_connection(account); + display_name = purple_connection_get_display_name(connection); + if(display_name != NULL) { + purple_chat_conversation_set_nick(chat, display_name); + const gchar *username = purple_account_get_username(account); + purple_chat_conversation_set_nick(chat, username); + if(purple_prefs_get_bool("/purple/logging/log_chats")) { + purple_conversation_set_logging(PURPLE_CONVERSATION(chat), TRUE); + g_object_unref(account); +purple_chat_conversation_dispose(GObject *obj) { + PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(obj); + PurpleChatConversationPrivate *priv = NULL; + priv = purple_chat_conversation_get_instance_private(chat); + g_hash_table_remove_all(priv->users); + G_OBJECT_CLASS(purple_chat_conversation_parent_class)->dispose(obj); +purple_chat_conversation_finalize(GObject *obj) { + PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(obj); + PurpleConversation *conv = PURPLE_CONVERSATION(chat); + PurpleConnection *gc = purple_conversation_get_connection(conv); + PurpleChatConversationPrivate *priv = NULL; + priv = purple_chat_conversation_get_instance_private(chat); + if(PURPLE_IS_CONNECTION(gc)) { + gint chat_id = purple_chat_conversation_get_id(chat); + * Close the window when the user tells us to, and let the protocol + * deal with the internals on its own time. Don't do this if the + * protocol already knows it left the chat. + if(!purple_chat_conversation_has_left(chat)) { + purple_serv_chat_leave(gc, chat_id); + * If they didn't call purple_serv_got_chat_left by now, it's too late. + * So we better do it for them before we destroy the thing. + if(!purple_chat_conversation_has_left(chat)) { + purple_serv_got_chat_left(gc, chat_id); + g_clear_pointer(&priv->users, g_hash_table_destroy); + g_list_free_full(priv->ignored, g_free); + g_clear_pointer(&priv->who, g_free); + g_clear_pointer(&priv->topic, g_free); + g_clear_pointer(&priv->nick, g_free); + G_OBJECT_CLASS(purple_chat_conversation_parent_class)->finalize(obj); +purple_chat_conversation_class_init(PurpleChatConversationClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + PurpleConversationClass *conv_class = PURPLE_CONVERSATION_CLASS(klass); + obj_class->constructed = purple_chat_conversation_constructed; + obj_class->dispose = purple_chat_conversation_dispose; + obj_class->finalize = purple_chat_conversation_finalize; + obj_class->get_property = purple_chat_conversation_get_property; + obj_class->set_property = purple_chat_conversation_set_property; + conv_class->write_message = chat_conversation_write_message; + * PurpleChatConversation::topic-who: + * The username who changed the topic last. + properties[PROP_TOPIC_WHO] = g_param_spec_string( + "topic-who", "who set topic", + "Who set the topic of the chat.", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + * PurpleChatConversation::topic: + * The text of the topic. + properties[PROP_TOPIC] = g_param_spec_string( + "The topic of the chat.", + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + * PurpleChatConversation::chat-id: + * The identifier of the chat. + properties[PROP_CHAT_ID] = g_param_spec_int( + "The identifier of the chat.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PurpleChatConversation::nick: + * The nickname of the user in the chat. + properties[PROP_NICK] = g_param_spec_string( + "The nickname of the user in a chat.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + * PurpleChatConversation::left: + * Whether the user has left the chat or not. + properties[PROP_LEFT] = g_param_spec_boolean( + "Whether the user has left the chat.", + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(obj_class, N_PROPERTIES, properties); +/****************************************************************************** + *****************************************************************************/ +PurpleChatConversation * +purple_chat_conversation_new(PurpleAccount *account, const gchar *name) { + PurpleChatConversation *chat = NULL; + PurpleConnection *connection = NULL; + g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL); + g_return_val_if_fail(name != NULL, NULL); + /* Check if this conversation already exists. */ + chat = purple_conversations_find_chat_with_account(name, account); + if(PURPLE_IS_CHAT_CONVERSATION(chat)) { + if(!purple_chat_conversation_has_left(chat)) { + purple_debug_warning("chat-conversation", "A chat named %s " + "already exists.", name); + connection = purple_account_get_connection(account); + if(!PURPLE_IS_CONNECTION(connection)) { + purple_debug_warning("chat-conversation", "Refusing to create chat " + "for disconnected account %s", + purple_account_get_username(account)); + return PURPLE_CHAT_CONVERSATION(g_object_new( + PURPLE_TYPE_CHAT_CONVERSATION, +purple_chat_conversation_get_users(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + priv = purple_chat_conversation_get_instance_private(chat); + return g_hash_table_get_values(priv->users); +purple_chat_conversation_get_users_count(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), 0); + priv = purple_chat_conversation_get_instance_private(chat); + return g_hash_table_size(priv->users); +purple_chat_conversation_ignore(PurpleChatConversation *chat, + PurpleChatConversationPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + g_return_if_fail(name != NULL); + priv = purple_chat_conversation_get_instance_private(chat); + /* Make sure the user isn't already ignored. */ + if(purple_chat_conversation_is_ignored_user(chat, name)) { + priv->ignored = g_list_prepend(priv->ignored, g_strdup(name)); +purple_chat_conversation_unignore(PurpleChatConversation *chat, + PurpleChatConversationPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + g_return_if_fail(name != NULL); + priv = purple_chat_conversation_get_instance_private(chat); + /* Make sure the user is actually ignored. */ + if(!purple_chat_conversation_is_ignored_user(chat, name)) { + item = g_list_find(priv->ignored, + purple_chat_conversation_get_ignored_user(chat, name)); + priv->ignored = g_list_delete_link(priv->ignored, item); +purple_chat_conversation_set_ignored(PurpleChatConversation *chat, + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + priv = purple_chat_conversation_get_instance_private(chat); + priv->ignored = ignored; +purple_chat_conversation_get_ignored(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + priv = purple_chat_conversation_get_instance_private(chat); +purple_chat_conversation_get_ignored_user(PurpleChatConversation *chat, + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + g_return_val_if_fail(user != NULL, NULL); + ignored = purple_chat_conversation_get_ignored(chat); + for(; ignored != NULL; ignored = ignored->next) { + const gchar *ign = (const gchar *)ignored->data; + if(!purple_utf8_strcasecmp(user, ign) || + ((*ign == '+' || *ign == '%') && + !purple_utf8_strcasecmp(user, ign + 1))) + if((*ign == '+' && !purple_utf8_strcasecmp(user, ign + 1)) || + (*ign != '+' && !purple_utf8_strcasecmp(user, ign))) +purple_chat_conversation_is_ignored_user(PurpleChatConversation *chat, + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), FALSE); + g_return_val_if_fail(user != NULL, FALSE); + return (purple_chat_conversation_get_ignored_user(chat, user) != NULL); +purple_chat_conversation_set_topic(PurpleChatConversation *chat, + const gchar *who, const gchar *topic) + PurpleChatConversationPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + priv = purple_chat_conversation_get_instance_private(chat); + g_clear_pointer(&priv->who, g_free); + g_clear_pointer(&priv->topic, g_free); + priv->who = g_strdup(who); + priv->topic = g_strdup(topic); + g_object_freeze_notify(obj); + g_object_notify_by_pspec(obj, properties[PROP_TOPIC_WHO]); + g_object_notify_by_pspec(obj, properties[PROP_TOPIC]); + g_object_thaw_notify(obj); + purple_conversation_update(PURPLE_CONVERSATION(chat), + PURPLE_CONVERSATION_UPDATE_TOPIC); + purple_signal_emit(purple_conversations_get_handle(), "chat-topic-changed", + chat, priv->who, priv->topic); +purple_chat_conversation_get_topic(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + priv = purple_chat_conversation_get_instance_private(chat); +purple_chat_conversation_get_topic_who(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + priv = purple_chat_conversation_get_instance_private(chat); +purple_chat_conversation_set_id(PurpleChatConversation *chat, gint id) { + PurpleChatConversationPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + priv = purple_chat_conversation_get_instance_private(chat); + g_object_notify_by_pspec(G_OBJECT(chat), properties[PROP_CHAT_ID]); +purple_chat_conversation_get_id(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), -1); + priv = purple_chat_conversation_get_instance_private(chat); +purple_chat_conversation_add_user(PurpleChatConversation *chat, + const gchar *user, const gchar *extra_msg, + PurpleChatUserFlags flags, + GList *users = g_list_append(NULL, (gchar *)user); + GList *extra_msgs = g_list_append(NULL, (gchar *)extra_msg); + GList *flags2 = g_list_append(NULL, GINT_TO_POINTER(flags)); + purple_chat_conversation_add_users(chat, users, extra_msgs, flags2, + g_list_free(extra_msgs); +purple_chat_conversation_add_users(PurpleChatConversation *chat, GList *users, + GList *extra_msgs, GList *flags, + PurpleConversation *conv; + PurpleConversationUiOps *ops; + PurpleChatUser *chatuser; + PurpleChatConversationPrivate *priv; + PurpleAccount *account; + PurpleProtocol *protocol; + GList *cbuddies = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + g_return_if_fail(users != NULL); + priv = purple_chat_conversation_get_instance_private(chat); + conv = PURPLE_CONVERSATION(chat); + ops = purple_conversation_get_ui_ops(conv); + account = purple_conversation_get_account(conv); + gc = purple_conversation_get_connection(conv); + g_return_if_fail(PURPLE_IS_CONNECTION(gc)); + protocol = purple_connection_get_protocol(gc); + g_return_if_fail(PURPLE_IS_PROTOCOL(protocol)); + handle = purple_conversations_get_handle(); + while(users != NULL && flags != NULL) { + const gchar *user = (const gchar *)users->data; + const gchar *alias = user; + PurpleChatUserFlags flag = GPOINTER_TO_INT(flags->data); + const gchar *extra_msg = (extra_msgs ? extra_msgs->data : NULL); + if(!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) { + if(purple_strequal(priv->nick, purple_normalize(account, user))) { + const gchar *alias2 = purple_account_get_private_alias(account); + const gchar *display_name = purple_connection_get_display_name(gc); + if(display_name != NULL) { + if((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), user)) != NULL) { + alias = purple_buddy_get_contact_alias(buddy); + quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(handle, + "chat-user-joining", chat, user, flag)) || + purple_chat_conversation_is_ignored_user(chat, user); + chatuser = purple_chat_user_new(chat, user, alias, flag); + g_hash_table_replace(priv->users, + g_strdup(purple_chat_user_get_name(chatuser)), + cbuddies = g_list_prepend(cbuddies, chatuser); + if(!quiet && new_arrivals) { + gchar *alias_esc = g_markup_escape_text(alias, -1); + if(extra_msg == NULL) { + tmp = g_strdup_printf(_("%s entered the room."), alias_esc); + gchar *extra_msg_esc = g_markup_escape_text(extra_msg, -1); + tmp = g_strdup_printf(_("%s [<I>%s</I>] entered the room."), + alias_esc, extra_msg_esc); + purple_conversation_write_system_message(conv, tmp, + PURPLE_MESSAGE_NO_LINKIFY); + purple_signal_emit(handle, "chat-user-joined", chat, user, flag, + if(extra_msgs != NULL) { + extra_msgs = extra_msgs->next; + cbuddies = g_list_sort(cbuddies, (GCompareFunc)purple_chat_user_compare); + if(ops != NULL && ops->chat_add_users != NULL) { + ops->chat_add_users(chat, cbuddies, new_arrivals); +purple_chat_conversation_rename_user(PurpleChatConversation *chat, + PurpleConversation *conv; + PurpleConversationUiOps *ops; + PurpleAccount *account; + PurpleProtocol *protocol; + PurpleChatUserFlags flags; + PurpleChatConversationPrivate *priv; + const gchar *new_alias = new_user; + gboolean is_me = FALSE; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + g_return_if_fail(old_user != NULL); + g_return_if_fail(new_user != NULL); + priv = purple_chat_conversation_get_instance_private(chat); + conv = PURPLE_CONVERSATION(chat); + ops = purple_conversation_get_ui_ops(conv); + account = purple_conversation_get_account(conv); + gc = purple_conversation_get_connection(conv); + g_return_if_fail(PURPLE_IS_CONNECTION(gc)); + protocol = purple_connection_get_protocol(gc); + g_return_if_fail(PURPLE_IS_PROTOCOL(protocol)); + if(purple_strequal(priv->nick, purple_normalize(account, old_user))) { + /* Note this for later. */ + if(!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) { + alias = purple_account_get_private_alias(account); + const gchar *display_name = purple_connection_get_display_name(gc); + if(display_name != NULL) { + new_alias = display_name; + } else if(!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) { + if((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), new_user)) != NULL) { + new_alias = purple_buddy_get_contact_alias(buddy); + flags = purple_chat_user_get_flags(purple_chat_conversation_find_user(chat, old_user)); + cb = purple_chat_user_new(chat, new_user, new_alias, flags); + g_hash_table_replace(priv->users, + g_strdup(purple_chat_user_get_name(cb)), cb); + if(ops != NULL && ops->chat_rename_user != NULL) { + ops->chat_rename_user(chat, old_user, new_user, new_alias); + cb = purple_chat_conversation_find_user(chat, old_user); + g_hash_table_remove(priv->users, purple_chat_user_get_name(cb)); + if(purple_chat_conversation_is_ignored_user(chat, old_user)) { + purple_chat_conversation_unignore(chat, old_user); + purple_chat_conversation_ignore(chat, new_user); + } else if(purple_chat_conversation_is_ignored_user(chat, new_user)) { + purple_chat_conversation_unignore(chat, new_user); + purple_chat_conversation_set_nick(chat, new_user); + if(purple_prefs_get_bool("/purple/conversations/chat/show_nick_change") && + !purple_chat_conversation_is_ignored_user(chat, new_user)) + gchar *escaped = g_markup_escape_text(new_user, -1); + g_snprintf(tmp, sizeof(tmp), _("You are now known as %s"), + const gchar *old_alias = old_user; + const gchar *new_alias = new_user; + if(!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) { + if((buddy = purple_blist_find_buddy(account, old_user)) != NULL) { + old_alias = purple_buddy_get_contact_alias(buddy); + if((buddy = purple_blist_find_buddy(account, new_user)) != NULL) { + new_alias = purple_buddy_get_contact_alias(buddy); + escaped = g_markup_escape_text(old_alias, -1); + escaped2 = g_markup_escape_text(new_alias, -1); + g_snprintf(tmp, sizeof(tmp), _("%s is now known as %s"), escaped, + purple_conversation_write_system_message(conv, tmp, + PURPLE_MESSAGE_NO_LINKIFY); +purple_chat_conversation_remove_user(PurpleChatConversation *chat, + const gchar *user, const gchar *reason) + GList *users = g_list_append(NULL, (gchar *)user); + purple_chat_conversation_remove_users(chat, users, reason); +purple_chat_conversation_remove_users(PurpleChatConversation *chat, + GList *users, const gchar *reason) + PurpleConversation *conv; + PurpleProtocol *protocol; + PurpleConversationUiOps *ops; + PurpleChatConversationPrivate *priv; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + g_return_if_fail(users != NULL); + priv = purple_chat_conversation_get_instance_private(chat); + conv = PURPLE_CONVERSATION(chat); + gc = purple_conversation_get_connection(conv); + g_return_if_fail(PURPLE_IS_CONNECTION(gc)); + protocol = purple_connection_get_protocol(gc); + g_return_if_fail(PURPLE_IS_PROTOCOL(protocol)); + ops = purple_conversation_get_ui_ops(conv); + handle = purple_conversations_get_handle(); + for(l = users; l != NULL; l = l->next) { + const gchar *user = (const gchar *)l->data; + quiet = GPOINTER_TO_INT(purple_signal_emit_return_1(handle, + "chat-user-leaving", chat, user, reason)) | + purple_chat_conversation_is_ignored_user(chat, user); + cb = purple_chat_conversation_find_user(chat, user); + g_hash_table_remove(priv->users, purple_chat_user_get_name(cb)); + /* NOTE: Don't remove them from ignored in case they re-enter. */ + const gchar *alias = user; + if(!(purple_protocol_get_options(protocol) & OPT_PROTO_UNIQUE_CHATNAME)) { + if((buddy = purple_blist_find_buddy(purple_connection_get_account(gc), user)) != NULL) { + alias = purple_buddy_get_contact_alias(buddy); + alias_esc = g_markup_escape_text(alias, -1); + if(reason == NULL || !*reason) { + tmp = g_strdup_printf(_("%s left the room."), alias_esc); + char *reason_esc = g_markup_escape_text(reason, -1); + tmp = g_strdup_printf(_("%s left the room (%s)."), + alias_esc, reason_esc); + purple_conversation_write_system_message(conv, tmp, + PURPLE_MESSAGE_NO_LINKIFY); + purple_signal_emit(handle, "chat-user-left", conv, user, reason); + if(ops != NULL && ops->chat_remove_users != NULL) { + ops->chat_remove_users(chat, users); +purple_chat_conversation_clear_users(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + PurpleConversationUiOps *ops = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + priv = purple_chat_conversation_get_instance_private(chat); + ops = purple_conversation_get_ui_ops(PURPLE_CONVERSATION(chat)); + names = g_hash_table_get_keys(priv->users); + if(ops != NULL && ops->chat_remove_users != NULL) { + ops->chat_remove_users(chat, names); + g_list_foreach(names, purple_chat_conversation_clear_users_helper, chat); + g_hash_table_remove_all(priv->users); +purple_chat_conversation_set_nick(PurpleChatConversation *chat, + PurpleChatConversationPrivate *priv = NULL; + PurpleAccount *account = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + priv = purple_chat_conversation_get_instance_private(chat); + account = purple_conversation_get_account(PURPLE_CONVERSATION(chat)); + priv->nick = g_strdup(purple_normalize(account, nick)); + g_object_notify_by_pspec(G_OBJECT(chat), properties[PROP_NICK]); +purple_chat_conversation_get_nick(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + priv = purple_chat_conversation_get_instance_private(chat); +invite_user_to_chat(gpointer data, PurpleRequestFields *fields) { + PurpleChatConversation *chat; + PurpleChatConversationPrivate *priv; + const gchar *user, *message; + chat = PURPLE_CHAT_CONVERSATION(data); + priv = purple_chat_conversation_get_instance_private(chat); + user = purple_request_fields_get_string(fields, "screenname"); + message = purple_request_fields_get_string(fields, "message"); + pc = purple_conversation_get_connection(PURPLE_CONVERSATION(chat)); + purple_serv_chat_invite(pc, priv->id, message, user); +purple_chat_conversation_invite_user(PurpleChatConversation *chat, + const gchar *user, const gchar *message, + PurpleAccount *account; + PurpleRequestFields *fields; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + if(user == NULL || *user == '\0' || message == NULL || *message == '\0') { + account = purple_conversation_get_account(PURPLE_CONVERSATION(chat)); + purple_serv_chat_invite(purple_account_get_connection(account), + purple_chat_conversation_get_id(chat), message, + fields = purple_request_fields_new(); + group = purple_request_field_group_new(_("Invite to chat")); + purple_request_fields_add_group(fields, group); + field = purple_request_field_string_new("screenname", _("Buddy"), user, + purple_request_field_group_add_field(group, field); + purple_request_field_set_required(field, TRUE); + purple_request_field_set_type_hint(field, "screenname"); + field = purple_request_field_string_new("message", _("Message"), message, + purple_request_field_group_add_field(group, field); + purple_request_fields(chat, _("Invite to chat"), NULL, + _("Please enter the name of the user you wish to " + "invite, along with an optional invite message."), + _("Invite"), G_CALLBACK(invite_user_to_chat), + purple_request_cpar_from_conversation(PURPLE_CONVERSATION(chat)), +purple_chat_conversation_has_user(PurpleChatConversation *chat, + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), FALSE); + g_return_val_if_fail(user != NULL, FALSE); + return (purple_chat_conversation_find_user(chat, user) != NULL); +purple_chat_conversation_leave(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat)); + priv = purple_chat_conversation_get_instance_private(chat); + if(!g_object_get_data(G_OBJECT(chat), "is-finalizing")) { + g_object_notify_by_pspec(G_OBJECT(chat), properties[PROP_LEFT]); + purple_conversation_update(PURPLE_CONVERSATION(chat), + PURPLE_CONVERSATION_UPDATE_CHATLEFT); +purple_chat_conversation_has_left(PurpleChatConversation *chat) { + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), TRUE); + priv = purple_chat_conversation_get_instance_private(chat); +purple_chat_conversation_find_user(PurpleChatConversation *chat, + PurpleChatConversationPrivate *priv = NULL; + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(chat), NULL); + g_return_val_if_fail(name != NULL, NULL); + priv = purple_chat_conversation_get_instance_private(chat); + return g_hash_table_lookup(priv->users, name); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purplechatconversation.h Mon Apr 05 22:24:57 2021 -0500
@@ -0,0 +1,383 @@
+ * Copyright (C) Pidgin Developers <devel@pidgin.im> + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses/>. +#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION) +# error "only <purple.h> may be included directly" +#ifndef PURPLE_CHAT_CONVERSATION_H +#define PURPLE_CHAT_CONVERSATION_H + * SECTION:purplechatconversation + * @section_id: libpurple-purplechatconversation + * @short_description: <filename>purplechatconversation.h</filename> + * @title: Chat Conversation Objects +#define PURPLE_TYPE_CHAT_CONVERSATION (purple_chat_conversation_get_type()) +#define PURPLE_CHAT_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversation)) +#define PURPLE_CHAT_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversationClass)) +#define PURPLE_IS_CHAT_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_CHAT_CONVERSATION)) +#define PURPLE_IS_CHAT_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_CHAT_CONVERSATION)) +#define PURPLE_CHAT_CONVERSATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversationClass)) +typedef struct _PurpleChatConversation PurpleChatConversation; +typedef struct _PurpleChatConversationClass PurpleChatConversationClass; +#include "purplechatuser.h" +#include "purpleimconversation.h" +#include "conversation.h" + * PurpleChatConversation: + * Structure representing a chat conversation instance. +struct _PurpleChatConversation { + PurpleConversation parent_object; + * PurpleChatConversationClass: + * Base class for all #PurpleChatConversation's +struct _PurpleChatConversationClass { + PurpleConversationClass parent_class; + * purple_chat_conversation_get_type: + * Returns: The #GType for the ChatConversation object. +GType purple_chat_conversation_get_type(void); + * purple_chat_conversation_new: + * @account: The account opening the conversation window on the purple user's + * @name: The name of the conversation. + * Creates a new chat conversation. + * Returns: The new conversation. +PurpleChatConversation *purple_chat_conversation_new(PurpleAccount *account, const gchar *name); + * purple_chat_conversation_get_users: + * Returns a list of users in the chat room. The members of the list + * are PurpleChatUser objects. + * Returns: (element-type PurpleChatUser) (transfer container): + * The list of users. Use g_list_free() when done +GList *purple_chat_conversation_get_users(PurpleChatConversation *chat); + * purple_chat_conversation_get_users_count: + * Returns count of users in the chat room. + * Returns: The count of users in the chat room. +guint purple_chat_conversation_get_users_count(PurpleChatConversation *chat); + * purple_chat_conversation_ignore: + * @name: The name of the user. + * Ignores a user in a chat room. +void purple_chat_conversation_ignore(PurpleChatConversation *chat, const gchar *name); + * purple_chat_conversation_unignore: + * @name: The name of the user. + * Unignores a user in a chat room. +void purple_chat_conversation_unignore(PurpleChatConversation *chat, const gchar *name); + * purple_chat_conversation_set_ignored: + * @ignored: (element-type utf8): The list of ignored users. + * Sets the list of ignored users in the chat room. + * Returns: (element-type utf8) (transfer none): The list passed. +GList *purple_chat_conversation_set_ignored(PurpleChatConversation *chat, GList *ignored); + * purple_chat_conversation_get_ignored: + * Returns the list of ignored users in the chat room. + * Returns: (element-type utf8) (transfer none): The list of ignored users. +GList *purple_chat_conversation_get_ignored(PurpleChatConversation *chat); + * purple_chat_conversation_get_ignored_user: + * @user: The user to check in the ignore list. + * Returns the actual name of the specified ignored user, if it exists in + * If the user found contains a prefix, such as '+' or '\@', this is also + * returned. The username passed to the function does not have to have this + * Returns: The ignored user if found, complete with prefixes, or %NULL +const gchar *purple_chat_conversation_get_ignored_user(PurpleChatConversation *chat, const gchar *user); + * purple_chat_conversation_is_ignored_user: + * Returns %TRUE if the specified user is ignored. + * Returns: %TRUE if the user is in the ignore list; %FALSE otherwise. +gboolean purple_chat_conversation_is_ignored_user(PurpleChatConversation *chat, const gchar *user); + * purple_chat_conversation_set_topic: + * @who: The user that set the topic. + * Sets the chat room's topic. +void purple_chat_conversation_set_topic(PurpleChatConversation *chat, const gchar *who, const gchar *topic); + * purple_chat_conversation_get_topic: + * Returns the chat room's topic. + * Returns: The chat's topic. +const gchar *purple_chat_conversation_get_topic(PurpleChatConversation *chat); + * purple_chat_conversation_get_topic_who: + * Returns who set the chat room's topic. + * Returns: Who set the topic. +const gchar *purple_chat_conversation_get_topic_who(PurpleChatConversation *chat); + * purple_chat_conversation_set_id: + * Sets the chat room's ID. +void purple_chat_conversation_set_id(PurpleChatConversation *chat, gint id); + * purple_chat_conversation_get_id: + * Gets the chat room's ID. +gint purple_chat_conversation_get_id(PurpleChatConversation *chat); + * purple_chat_conversation_add_user: + * @user: The user to add. + * @extra_msg: An extra message to display with the join message. + * @flags: The users flags + * @new_arrival: Decides whether or not to show a join notice. + * Adds a user to a chat. +void purple_chat_conversation_add_user(PurpleChatConversation *chat, const gchar *user, const gchar *extra_msg, PurpleChatUserFlags flags, gboolean new_arrival); + * purple_chat_conversation_add_users: + * @users: (element-type utf8): The list of users to add. + * @extra_msgs: (element-type utf8) (nullable): An extra message to display + * with the join message for each user. This list may be shorter + * than @users, in which case, the users after the end of + * extra_msgs will not have an extra message. By extension, this + * means that extra_msgs can simply be %NULL and none of the users + * will have an extra message. + * @flags: (element-type PurpleChatUserFlags): The list of flags for each user. + * This list data should be an int converted to pointer using + * GINT_TO_POINTER(flag) + * @new_arrivals: Decides whether or not to show join notices. + * Adds a list of users to a chat. + * The data is copied from @users, @extra_msgs, and @flags, so it is up to + * the caller to free this list after calling this function. +void purple_chat_conversation_add_users(PurpleChatConversation *chat, GList *users, GList *extra_msgs, GList *flags, gboolean new_arrivals); + * purple_chat_conversation_rename_user: + * @old_user: The old username. + * @new_user: The new username. + * Renames a user in a chat. +void purple_chat_conversation_rename_user(PurpleChatConversation *chat, const gchar *old_user, const gchar *new_user); + * purple_chat_conversation_remove_user: + * @user: The user that is being removed. + * @reason: The optional reason given for the removal. Can be %NULL. + * Removes a user from a chat, optionally with a reason. + * It is up to the developer to free this list after calling this function. +void purple_chat_conversation_remove_user(PurpleChatConversation *chat, const gchar *user, const gchar *reason); + * purple_chat_conversation_remove_users: + * @users: (element-type utf8): The users that are being removed. + * @reason: The optional reason given for the removal. Can be %NULL. + * Removes a list of users from a chat, optionally with a single reason. +void purple_chat_conversation_remove_users(PurpleChatConversation *chat, GList *users, const gchar *reason); + * purple_chat_conversation_has_user: + * @user: The user to look for. + * Checks if a user is in a chat + * Returns: %TRUE if the user is in the chat, %FALSE if not +gboolean purple_chat_conversation_has_user(PurpleChatConversation *chat, const gchar *user); + * purple_chat_conversation_clear_users: + * Clears all users from a chat. +void purple_chat_conversation_clear_users(PurpleChatConversation *chat); + * purple_chat_conversation_set_nick: + * Sets your nickname (used for hilighting) for a chat. +void purple_chat_conversation_set_nick(PurpleChatConversation *chat, const gchar *nick); + * purple_chat_conversation_get_nick: + * Gets your nickname (used for hilighting) for a chat. +const gchar *purple_chat_conversation_get_nick(PurpleChatConversation *chat); + * purple_chat_conversation_leave: + * Lets the core know we left a chat, without destroying it. + * Called from purple_serv_got_chat_left(). +void purple_chat_conversation_leave(PurpleChatConversation *chat); + * purple_chat_conversation_find_user: + * @name: The name of the chat user to find. + * Find a chat user in a chat + * Returns: (transfer none): The #PurpleChatUser with the name referred by +PurpleChatUser *purple_chat_conversation_find_user(PurpleChatConversation *chat, const gchar *name); + * purple_chat_conversation_invite_user: + * @user: The user to invite to the chat. + * @message: The message to send with the invitation. + * @confirm: Prompt before sending the invitation. The user is always prompted + * if either @user or @message is %NULL. + * Invite a user to a chat. + * The user will be prompted to enter the user's name or a message if one is +void purple_chat_conversation_invite_user(PurpleChatConversation *chat, const gchar *user, const gchar *message, gboolean confirm); + * purple_chat_conversation_has_left: + * Gets whether we're no longer in this chat, and just left the window open. + * Returns: %TRUE if we left the chat already, %FALSE if we're still there. +gboolean purple_chat_conversation_has_left(PurpleChatConversation *chat); +#endif /* PURPLE_CHAT_CONVERSATION_H */ --- a/libpurple/purplechatuser.h Mon Apr 05 20:20:33 2021 -0500
+++ b/libpurple/purplechatuser.h Mon Apr 05 22:24:57 2021 -0500
@@ -82,7 +82,7 @@
G_DECLARE_FINAL_TYPE(PurpleChatUser, purple_chat_user, PURPLE, CHAT_USER,
-#include <libpurple/conversationtypes.h>
+#include <libpurple/purplechatconversation.h> --- a/libpurple/purpleprotocolim.h Mon Apr 05 20:20:33 2021 -0500
+++ b/libpurple/purpleprotocolim.h Mon Apr 05 22:24:57 2021 -0500
@@ -41,7 +41,6 @@
#include <libpurple/connection.h>
-#include <libpurple/conversationtypes.h>
#define PURPLE_TYPE_PROTOCOL_IM (purple_protocol_im_get_type())
G_DECLARE_INTERFACE(PurpleProtocolIM, purple_protocol_im, PURPLE, PROTOCOL_IM,
--- a/po/POTFILES.in Mon Apr 05 20:20:33 2021 -0500
+++ b/po/POTFILES.in Mon Apr 05 22:24:57 2021 -0500
@@ -31,13 +31,13 @@
+libpurple/chatconversation.c libpurple/circularbuffer.c
libpurple/conversations.c
-libpurple/conversationtypes.c