gobjectification: d1809247: Split blist.c into contact.c, group.c, b...
aluink at soc.pidgin.im
aluink at soc.pidgin.im
Wed Jun 17 19:05:28 EDT 2009
-----------------------------------------------------------------
Revision: d18092473b4d9d6e95c12c1d4ad0dff3306271c9
Ancestor: 51a28c52860565118364a83cae30a6305c9a3319
Author: aluink at soc.pidgin.im
Date: 2009-06-17T22:47:25
Branch: im.pidgin.gobjectification
URL: http://d.pidgin.im/viewmtn/revision/info/d18092473b4d9d6e95c12c1d4ad0dff3306271c9
Added files:
libpurple/blist-node.c libpurple/buddy.c libpurple/chat.c
libpurple/contact.c libpurple/group.c
Modified files:
libpurple/Makefile.am libpurple/blist.c libpurple/blist.h
ChangeLog:
Split blist.c into contact.c, group.c, blist-node.c, buddy.c, chat.c
Rough for now, clean up is continuing.
-------------- next part --------------
============================================================
--- libpurple/blist-node.c f2ad7fe515dcdce498d66d7095e6144be5da8ebf
+++ libpurple/blist-node.c f2ad7fe515dcdce498d66d7095e6144be5da8ebf
@@ -0,0 +1,635 @@
+/*
+ * purple
+ *
+ * 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
+ * source distribution.
+ *
+ * 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
+ *
+ */
+#define _PURPLE_BLIST_NODE_C_
+#define _BLIST_HELPERS_
+
+#include "internal.h"
+#include "blist.h"
+#include "conversation.h"
+#include "dbus-maybe.h"
+#include "debug.h"
+#include "notify.h"
+#include "prefs.h"
+#include "privacy.h"
+#include "prpl.h"
+#include "server.h"
+#include "signals.h"
+#include "util.h"
+#include "value.h"
+#include "xmlnode.h"
+
+PurpleBlistNode *
+purple_blist_get_last_sibling(PurpleBlistNode *node)
+{
+ PurpleBlistNode *n = node;
+ if (!n)
+ return NULL;
+ while (n->next)
+ n = n->next;
+ return n;
+}
+
+PurpleBlistNode *
+purple_blist_get_last_child(PurpleBlistNode *node)
+{
+ if (!node)
+ return NULL;
+ return purple_blist_get_last_sibling(node->child);
+}
+
+void
+parse_setting(PurpleBlistNode *node, xmlnode *setting)
+{
+ const char *name = xmlnode_get_attrib(setting, "name");
+ const char *type = xmlnode_get_attrib(setting, "type");
+ char *value = xmlnode_get_data(setting);
+
+ if (!value)
+ return;
+
+ if (!type || purple_strequal(type, "string"))
+ purple_blist_node_set_string(node, name, value);
+ else if (purple_strequal(type, "bool"))
+ purple_blist_node_set_bool(node, name, atoi(value));
+ else if (purple_strequal(type, "int"))
+ purple_blist_node_set_int(node, name, atoi(value));
+
+ g_free(value);
+}
+
+/*****************************************************************************
+ * Public API functions *
+ *****************************************************************************/
+
+static PurpleBlistNode *get_next_node(PurpleBlistNode *node, gboolean godeep)
+{
+ if (node == NULL)
+ return NULL;
+
+ if (godeep && node->child)
+ return node->child;
+
+ if (node->next)
+ return node->next;
+
+ return get_next_node(node->parent, FALSE);
+}
+
+PurpleBlistNode *purple_blist_node_next(PurpleBlistNode *node, gboolean offline)
+{
+ PurpleBlistNode *ret = node;
+
+ if (offline)
+ return get_next_node(ret, TRUE);
+ do
+ {
+ ret = get_next_node(ret, TRUE);
+ } while (ret && PURPLE_BLIST_NODE_IS_BUDDY(ret) &&
+ !purple_account_is_connected(purple_buddy_get_account((PurpleBuddy *)ret)));
+
+ return ret;
+}
+
+PurpleBlistNode *purple_blist_node_get_parent(PurpleBlistNode *node)
+{
+ return node ? node->parent : NULL;
+}
+
+PurpleBlistNode *purple_blist_node_get_first_child(PurpleBlistNode *node)
+{
+ return node ? node->child : NULL;
+}
+
+PurpleBlistNode *purple_blist_node_get_sibling_next(PurpleBlistNode *node)
+{
+ return node? node->next : NULL;
+}
+
+PurpleBlistNode *purple_blist_node_get_sibling_prev(PurpleBlistNode *node)
+{
+ return node? node->prev : NULL;
+}
+
+void *
+purple_blist_node_get_ui_data(const PurpleBlistNode *node)
+{
+ g_return_val_if_fail(node, NULL);
+
+ return node->ui_data;
+}
+
+void
+purple_blist_node_set_ui_data(PurpleBlistNode *node, void *ui_data) {
+ g_return_if_fail(node);
+
+ node->ui_data = ui_data;
+}
+
+void
+purple_blist_update_node_icon(PurpleBlistNode *node)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+
+ g_return_if_fail(node != NULL);
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), node);
+}
+
+void purple_blist_add_chat(PurpleChat *chat, PurpleGroup *group, PurpleBlistNode *node)
+{
+ PurpleBlistNode *cnode = (PurpleBlistNode*)chat;
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+
+ g_return_if_fail(chat != NULL);
+ g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT((PurpleBlistNode *)chat));
+
+ if (node == NULL) {
+ if (group == NULL)
+ group = purple_group_new(_("Chats"));
+
+ /* Add group to blist if isn't already on it. Fixes #2752. */
+ if (!purple_find_group(group->name)) {
+ purple_blist_add_group(group,
+ purple_blist_get_last_sibling(purple_blist_get_list()->root));
+ }
+ } else {
+ group = (PurpleGroup*)node->parent;
+ }
+
+ /* if we're moving to overtop of ourselves, do nothing */
+ if (cnode == node)
+ return;
+
+ if (cnode->parent) {
+ /* This chat was already in the list and is
+ * being moved.
+ */
+ ((PurpleGroup *)cnode->parent)->totalsize--;
+ if (purple_account_is_connected(chat->account)) {
+ ((PurpleGroup *)cnode->parent)->online--;
+ ((PurpleGroup *)cnode->parent)->currentsize--;
+ }
+ if (cnode->next)
+ cnode->next->prev = cnode->prev;
+ if (cnode->prev)
+ cnode->prev->next = cnode->next;
+ if (cnode->parent->child == cnode)
+ cnode->parent->child = cnode->next;
+
+ if (ops && ops->remove)
+ ops->remove(purple_blist_get_list(), cnode);
+ /* ops->remove() cleaned up the cnode's ui_data, so we need to
+ * reinitialize it */
+ if (ops && ops->new_node)
+ ops->new_node(cnode);
+
+ purple_blist_schedule_save();
+ }
+
+ if (node != NULL) {
+ if (node->next)
+ node->next->prev = cnode;
+ cnode->next = node->next;
+ cnode->prev = node;
+ cnode->parent = node->parent;
+ node->next = cnode;
+ ((PurpleGroup *)node->parent)->totalsize++;
+ if (purple_account_is_connected(chat->account)) {
+ ((PurpleGroup *)node->parent)->online++;
+ ((PurpleGroup *)node->parent)->currentsize++;
+ }
+ } else {
+ if (((PurpleBlistNode *)group)->child)
+ ((PurpleBlistNode *)group)->child->prev = cnode;
+ cnode->next = ((PurpleBlistNode *)group)->child;
+ cnode->prev = NULL;
+ ((PurpleBlistNode *)group)->child = cnode;
+ cnode->parent = (PurpleBlistNode *)group;
+ group->totalsize++;
+ if (purple_account_is_connected(chat->account)) {
+ group->online++;
+ group->currentsize++;
+ }
+ }
+
+ purple_blist_schedule_save();
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode *)cnode);
+
+ purple_signal_emit(purple_blist_get_handle(), "blist-node-added",
+ cnode);
+}
+
+void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node)
+{
+ PurpleBlistNode *cnode, *bnode;
+ PurpleGroup *g;
+ PurpleContact *c;
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ struct _purple_hbuddy *hb, *hb2;
+ GHashTable *account_buddies;
+
+ g_return_if_fail(buddy != NULL);
+ g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY((PurpleBlistNode*)buddy));
+
+ bnode = (PurpleBlistNode *)buddy;
+
+ /* if we're moving to overtop of ourselves, do nothing */
+ if (bnode == node || (!node && bnode->parent &&
+ contact && bnode->parent == (PurpleBlistNode*)contact
+ && bnode == bnode->parent->child))
+ return;
+
+ if (node && PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+ c = (PurpleContact*)node->parent;
+ g = (PurpleGroup*)node->parent->parent;
+ } else if (contact) {
+ c = contact;
+ g = PURPLE_GROUP(PURPLE_BLIST_NODE(c)->parent);
+ } else {
+ g = group;
+ if (g == NULL)
+ g = purple_group_new(_("Buddies"));
+ /* Add group to blist if isn't already on it. Fixes #2752. */
+ if (!purple_find_group(g->name)) {
+ purple_blist_add_group(g,
+ purple_blist_get_last_sibling(purple_blist_get_list()->root));
+ }
+ c = purple_contact_new();
+ purple_blist_add_contact(c, g,
+ purple_blist_get_last_child((PurpleBlistNode*)g));
+ }
+
+ cnode = (PurpleBlistNode *)c;
+
+ if (bnode->parent) {
+ if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
+ ((PurpleContact*)bnode->parent)->online--;
+ if (((PurpleContact*)bnode->parent)->online == 0)
+ ((PurpleGroup*)bnode->parent->parent)->online--;
+ }
+ if (purple_account_is_connected(buddy->account)) {
+ ((PurpleContact*)bnode->parent)->currentsize--;
+ if (((PurpleContact*)bnode->parent)->currentsize == 0)
+ ((PurpleGroup*)bnode->parent->parent)->currentsize--;
+ }
+ ((PurpleContact*)bnode->parent)->totalsize--;
+ /* the group totalsize will be taken care of by remove_contact below */
+
+ if (bnode->parent->parent != (PurpleBlistNode*)g)
+ serv_move_buddy(buddy, (PurpleGroup *)bnode->parent->parent, g);
+
+ if (bnode->next)
+ bnode->next->prev = bnode->prev;
+ if (bnode->prev)
+ bnode->prev->next = bnode->next;
+ if (bnode->parent->child == bnode)
+ bnode->parent->child = bnode->next;
+
+ if (ops && ops->remove)
+ ops->remove(purple_blist_get_list(), bnode);
+
+ purple_blist_schedule_save();
+
+ if (bnode->parent->parent != (PurpleBlistNode*)g) {
+ hb = g_new(struct _purple_hbuddy, 1);
+ hb->name = g_strdup(purple_normalize(buddy->account, buddy->name));
+ hb->account = buddy->account;
+ hb->group = bnode->parent->parent;
+ g_hash_table_remove(purple_blist_get_list()->buddies, hb);
+
+ account_buddies = g_hash_table_lookup(purple_blist_get_buddies_cache(), buddy->account);
+ g_hash_table_remove(account_buddies, hb);
+
+ g_free(hb->name);
+ g_free(hb);
+ }
+
+ if (!bnode->parent->child) {
+ purple_blist_remove_contact((PurpleContact*)bnode->parent);
+ } else {
+ purple_contact_invalidate_priority_buddy((PurpleContact*)bnode->parent);
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), bnode->parent);
+ }
+ }
+
+ if (node && PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+ if (node->next)
+ node->next->prev = bnode;
+ bnode->next = node->next;
+ bnode->prev = node;
+ bnode->parent = node->parent;
+ node->next = bnode;
+ } else {
+ if (cnode->child)
+ cnode->child->prev = bnode;
+ bnode->prev = NULL;
+ bnode->next = cnode->child;
+ cnode->child = bnode;
+ bnode->parent = cnode;
+ }
+
+ if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
+ if (++(PURPLE_CONTACT(bnode->parent)->online) == 1)
+ PURPLE_GROUP(bnode->parent->parent)->online++;
+ }
+ if (purple_account_is_connected(buddy->account)) {
+ if (++(PURPLE_CONTACT(bnode->parent)->currentsize) == 1)
+ PURPLE_GROUP(bnode->parent->parent)->currentsize++;
+ }
+ PURPLE_CONTACT(bnode->parent)->totalsize++;
+
+ hb = g_new(struct _purple_hbuddy, 1);
+ hb->name = g_strdup(purple_normalize(buddy->account, buddy->name));
+ hb->account = buddy->account;
+ hb->group = ((PurpleBlistNode*)buddy)->parent->parent;
+
+ g_hash_table_replace(purple_blist_get_list()->buddies, hb, buddy);
+
+ account_buddies = g_hash_table_lookup(purple_blist_get_buddies_cache(), buddy->account);
+
+ hb2 = g_new(struct _purple_hbuddy, 1);
+ hb2->name = g_strdup(hb->name);
+ hb2->account = buddy->account;
+ hb2->group = ((PurpleBlistNode*)buddy)->parent->parent;
+
+ g_hash_table_replace(account_buddies, hb2, buddy);
+
+ purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
+
+ purple_blist_schedule_save();
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode*)buddy);
+
+ /* Signal that the buddy has been added */
+ purple_signal_emit(purple_blist_get_handle(), "buddy-added", buddy);
+
+ purple_signal_emit(purple_blist_get_handle(), "blist-node-added",
+ PURPLE_BLIST_NODE(buddy));
+}
+
+void purple_blist_merge_contact(PurpleContact *source, PurpleBlistNode *node)
+{
+ PurpleBlistNode *sourcenode = (PurpleBlistNode*)source;
+ PurpleBlistNode *targetnode;
+ PurpleBlistNode *prev, *cur, *next;
+ PurpleContact *target;
+g_return_if_fail(source != NULL);
+ g_return_if_fail(node != NULL);
+
+ if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
+ target = (PurpleContact *)node;
+ prev = purple_blist_get_last_child(node);
+ } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
+ target = (PurpleContact *)node->parent;
+ prev = node;
+ } else {
+ return;
+ }
+
+ if (source == target || !target)
+ return;
+
+ targetnode = (PurpleBlistNode *)target;
+ next = sourcenode->child;
+
+ while (next) {
+ cur = next;
+ next = cur->next;
+ if (PURPLE_BLIST_NODE_IS_BUDDY(cur)) {
+ purple_blist_add_buddy((PurpleBuddy *)cur, target, NULL, prev);
+ prev = cur;
+ }
+ }
+}
+
+void
+purple_blist_node_destroy(PurpleBlistNode *node)
+{
+ PurpleBlistUiOps *ui_ops;
+ PurpleBlistNode *child, *next_child;
+
+ ui_ops = purple_blist_get_ui_ops();
+ child = node->child;
+ while (child) {
+ next_child = child->next;
+ purple_blist_node_destroy(child);
+ child = next_child;
+ }
+
+ /* Allow the UI to free data */
+ node->parent = NULL;
+ node->child = NULL;
+ node->next = NULL;
+ node->prev = NULL;
+ if (ui_ops && ui_ops->remove)
+ ui_ops->remove(purple_blist_get_list(), node);
+
+ if (PURPLE_BLIST_NODE_IS_BUDDY(node))
+ purple_buddy_destroy((PurpleBuddy*)node);
+ else if (PURPLE_BLIST_NODE_IS_CHAT(node))
+ purple_chat_destroy((PurpleChat*)node);
+ else if (PURPLE_BLIST_NODE_IS_CONTACT(node))
+ purple_contact_destroy((PurpleContact*)node);
+ else if (PURPLE_BLIST_NODE_IS_GROUP(node))
+ purple_group_destroy((PurpleGroup*)node);
+}
+
+void purple_blist_node_initialize_settings(PurpleBlistNode *node)
+{
+ if (node->settings)
+ return;
+
+ node->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+ (GDestroyNotify)purple_g_value_slice_free);
+}
+
+void purple_blist_node_remove_setting(PurpleBlistNode *node, const char *key)
+{
+ g_return_if_fail(node != NULL);
+ g_return_if_fail(node->settings != NULL);
+ g_return_if_fail(key != NULL);
+
+ g_hash_table_remove(node->settings, key);
+
+ purple_blist_schedule_save();
+}
+
+void
+purple_blist_node_set_flags(PurpleBlistNode *node, PurpleBlistNodeFlags flags)
+{
+ g_return_if_fail(node != NULL);
+
+ node->flags = flags;
+}
+
+PurpleBlistNodeFlags
+purple_blist_node_get_flags(PurpleBlistNode *node)
+{
+ g_return_val_if_fail(node != NULL, 0);
+
+ return node->flags;
+}
+
+PurpleBlistNodeType
+purple_blist_node_get_type(PurpleBlistNode *node)
+{
+ g_return_val_if_fail(node != NULL, PURPLE_BLIST_OTHER_NODE);
+ return node->type;
+}
+
+gboolean
+purple_blist_node_has_setting(PurpleBlistNode *node,
+ const char *key)
+{
+ g_return_val_if_fail(node != NULL, FALSE);
+ g_return_val_if_fail(node->settings != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+
+ return (g_hash_table_lookup(node->settings, key) != NULL);
+}
+
+void
+purple_blist_node_set_bool(PurpleBlistNode* node, const char *key, gboolean data)
+{
+ GValue *value;
+
+ g_return_if_fail(node != NULL);
+ g_return_if_fail(node->settings != NULL);
+ g_return_if_fail(key != NULL);
+
+ value = purple_g_value_slice_new(G_TYPE_BOOLEAN);
+ g_value_set_boolean(value, data);
+
+ g_hash_table_replace(node->settings, g_strdup(key), value);
+
+ purple_blist_schedule_save();
+}
+
+gboolean
+purple_blist_node_get_bool(PurpleBlistNode* node, const char *key)
+{
+ GValue *value;
+
+ g_return_val_if_fail(node != NULL, FALSE);
+ g_return_val_if_fail(node->settings != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+
+ value = g_hash_table_lookup(node->settings, key);
+
+ if (value == NULL)
+ return FALSE;
+
+ g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(value), FALSE);
+
+ return g_value_get_boolean(value);
+}
+
+void
+purple_blist_node_set_int(PurpleBlistNode* node, const char *key, int data)
+{
+ GValue *value;
+
+ g_return_if_fail(node != NULL);
+ g_return_if_fail(node->settings != NULL);
+ g_return_if_fail(key != NULL);
+
+ value = purple_g_value_slice_new(G_TYPE_INT);
+ g_value_set_int(value, data);
+
+ g_hash_table_replace(node->settings, g_strdup(key), value);
+
+ purple_blist_schedule_save();
+}
+
+int
+purple_blist_node_get_int(PurpleBlistNode* node, const char *key)
+{
+ GValue *value;
+
+ g_return_val_if_fail(node != NULL, 0);
+ g_return_val_if_fail(node->settings != NULL, 0);
+ g_return_val_if_fail(key != NULL, 0);
+
+ value = g_hash_table_lookup(node->settings, key);
+
+ if (value == NULL)
+ return 0;
+
+ g_return_val_if_fail(G_VALUE_HOLDS_INT(value), 0);
+
+ return g_value_get_int(value);
+}
+
+void
+purple_blist_node_set_string(PurpleBlistNode* node, const char *key, const char *data)
+{
+ GValue *value;
+
+ g_return_if_fail(node != NULL);
+ g_return_if_fail(node->settings != NULL);
+ g_return_if_fail(key != NULL);
+
+ value = purple_g_value_slice_new(G_TYPE_STRING);
+ g_value_set_string(value, data);
+
+ g_hash_table_replace(node->settings, g_strdup(key), value);
+
+ purple_blist_schedule_save();
+}
+
+const char *
+purple_blist_node_get_string(PurpleBlistNode* node, const char *key)
+{
+ GValue *value;
+
+ g_return_val_if_fail(node != NULL, NULL);
+ g_return_val_if_fail(node->settings != NULL, NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+
+ value = g_hash_table_lookup(node->settings, key);
+
+ if (value == NULL)
+ return NULL;
+
+ g_return_val_if_fail(G_VALUE_HOLDS_STRING(value), NULL);
+
+ return g_value_get_string(value);
+}
+
+GList *
+purple_blist_node_get_extended_menu(PurpleBlistNode *n)
+{
+ GList *menu = NULL;
+
+ g_return_val_if_fail(n != NULL, NULL);
+
+ purple_signal_emit(purple_blist_get_handle(),
+ "blist-node-extended-menu",
+ n, &menu);
+ return menu;
+}
============================================================
--- libpurple/buddy.c cb402e709299a42ecc929e46abfc9d6bcd031df7
+++ libpurple/buddy.c cb402e709299a42ecc929e46abfc9d6bcd031df7
@@ -0,0 +1,565 @@
+/*
+ * purple
+ *
+ * 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
+ * source distribution.
+ *
+ * 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
+ *
+ */
+#define _PURPLE_BUDDY_C_
+#define _BLIST_HELPERS_
+
+#include "internal.h"
+#include "blist.h"
+#include "conversation.h"
+#include "dbus-maybe.h"
+#include "debug.h"
+#include "notify.h"
+#include "prefs.h"
+#include "privacy.h"
+#include "prpl.h"
+#include "server.h"
+#include "signals.h"
+#include "util.h"
+#include "value.h"
+#include "xmlnode.h"
+
+void
+parse_buddy(PurpleGroup *group, PurpleContact *contact, xmlnode *bnode)
+{
+ PurpleAccount *account;
+ PurpleBuddy *buddy;
+ char *name = NULL, *alias = NULL;
+ const char *acct_name, *proto, *protocol;
+ xmlnode *x;
+
+ acct_name = xmlnode_get_attrib(bnode, "account");
+ protocol = xmlnode_get_attrib(bnode, "protocol");
+ protocol = _purple_oscar_convert(acct_name, protocol); /* XXX: Remove */
+ proto = xmlnode_get_attrib(bnode, "proto");
+ proto = _purple_oscar_convert(acct_name, proto); /* XXX: Remove */
+
+ if (!acct_name || (!proto && !protocol))
+ return;
+
+ account = purple_accounts_find(acct_name, proto ? proto : protocol);
+
+ if (!account)
+ return;
+
+ if ((x = xmlnode_get_child(bnode, "name")))
+ name = xmlnode_get_data(x);
+
+ if (!name)
+ return;
+
+ if ((x = xmlnode_get_child(bnode, "alias")))
+ alias = xmlnode_get_data(x);
+
+ buddy = purple_buddy_new(account, name, alias);
+ purple_blist_add_buddy(buddy, contact, group,
+ purple_blist_get_last_child((PurpleBlistNode*)contact));
+
+ for (x = xmlnode_get_child(bnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
+ parse_setting((PurpleBlistNode*)buddy, x);
+ }
+
+ g_free(name);
+ g_free(alias);
+}
+
+static void
+append_buddy(gpointer key, gpointer value, gpointer user_data)
+{
+ GSList **list = user_data;
+ *list = g_slist_prepend(*list, value);
+}
+
+GSList *
+purple_blist_get_buddies()
+{
+ GSList *buddies = NULL;
+
+ if (!purple_blist_get_list())
+ return NULL;
+
+ g_hash_table_foreach(purple_blist_get_list()->buddies, append_buddy, &buddies);
+ return buddies;
+}
+
+void
+purple_blist_update_buddy_status(PurpleBuddy *buddy, PurpleStatus *old_status)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurplePresence *presence;
+ PurpleStatus *status;
+ PurpleBlistNode *cnode;
+
+ g_return_if_fail(buddy != NULL);
+
+ presence = purple_buddy_get_presence(buddy);
+ status = purple_presence_get_active_status(presence);
+
+ purple_debug_info("blist", "Updating buddy status for %s (%s)\n",
+ buddy->name, purple_account_get_protocol_name(buddy->account));
+
+ if (purple_status_is_online(status) &&
+ !purple_status_is_online(old_status)) {
+
+ purple_signal_emit(purple_blist_get_handle(), "buddy-signed-on", buddy);
+
+ cnode = buddy->node.parent;
+ if (++(PURPLE_CONTACT(cnode)->online) == 1)
+ PURPLE_GROUP(cnode->parent)->online++;
+ } else if (!purple_status_is_online(status) &&
+ purple_status_is_online(old_status)) {
+
+ purple_blist_node_set_int(&buddy->node, "last_seen", time(NULL));
+ purple_signal_emit(purple_blist_get_handle(), "buddy-signed-off", buddy);
+
+ cnode = buddy->node.parent;
+ if (--(PURPLE_CONTACT(cnode)->online) == 0)
+ PURPLE_GROUP(cnode->parent)->online--;
+ } else {
+ purple_signal_emit(purple_blist_get_handle(),
+ "buddy-status-changed", buddy, old_status,
+ status);
+ }
+
+ /*
+ * This function used to only call the following two functions if one of
+ * the above signals had been triggered, but that's not good, because
+ * if someone's away message changes and they don't go from away to back
+ * to away then no signal is triggered.
+ *
+ * It's a safe assumption that SOMETHING called this function. PROBABLY
+ * because something, somewhere changed. Calling the stuff below
+ * certainly won't hurt anything. Unless you're on a K6-2 300.
+ */
+ purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode *)buddy);
+}
+
+void
+purple_blist_update_buddy_icon(PurpleBuddy *buddy)
+{
+ purple_blist_update_node_icon((PurpleBlistNode *)buddy);
+}
+
+/*
+ * TODO: Maybe remove the call to this from server.c and call it
+ * from oscar.c and toc.c instead?
+ */
+void purple_blist_rename_buddy(PurpleBuddy *buddy, const char *name)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ struct _purple_hbuddy *hb, *hb2;
+ GHashTable *account_buddies;
+
+ g_return_if_fail(buddy != NULL);
+
+ hb = g_new(struct _purple_hbuddy, 1);
+ hb->name = g_strdup(purple_normalize(buddy->account, buddy->name));
+ hb->account = buddy->account;
+ hb->group = ((PurpleBlistNode *)buddy)->parent->parent;
+ g_hash_table_remove(purple_blist_get_list()->buddies, hb);
+
+ account_buddies = g_hash_table_lookup(purple_blist_get_buddies_cache(), buddy->account);
+ g_hash_table_remove(account_buddies, hb);
+
+ g_free(hb->name);
+ hb->name = g_strdup(purple_normalize(buddy->account, name));
+ g_hash_table_replace(purple_blist_get_list()->buddies, hb, buddy);
+
+ hb2 = g_new(struct _purple_hbuddy, 1);
+ hb2->name = g_strdup(hb->name);
+ hb2->account = buddy->account;
+ hb2->group = ((PurpleBlistNode *)buddy)->parent->parent;
+
+ g_hash_table_replace(account_buddies, hb2, buddy);
+
+ g_free(buddy->name);
+ buddy->name = g_strdup(name);
+
+ purple_blist_schedule_save();
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode *)buddy);
+}
+
+void purple_blist_alias_buddy(PurpleBuddy *buddy, const char *alias)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurpleConversation *conv;
+ char *old_alias;
+ char *new_alias = NULL;
+
+ g_return_if_fail(buddy != NULL);
+
+ if ((alias != NULL) && (*alias != '\0'))
+ new_alias = purple_utf8_strip_unprintables(alias);
+
+ if (!purple_strings_are_different(buddy->alias, new_alias)) {
+ g_free(new_alias);
+ return;
+ }
+
+ old_alias = buddy->alias;
+
+ if ((new_alias != NULL) && (*new_alias != '\0'))
+ buddy->alias = g_strdup(alias);
+ else {
+ buddy->alias = NULL;
+ g_free(new_alias); /* could be "\0" */
+ }
+
+ purple_blist_schedule_save();
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode *)buddy);
+
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy->name,
+ buddy->account);
+ if (conv)
+ purple_conversation_autoset_title(conv);
+
+ purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
+ buddy, old_alias);
+ g_free(old_alias);
+}
+
+void purple_blist_server_alias_buddy(PurpleBuddy *buddy, const char *alias)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurpleConversation *conv;
+ char *old_alias;
+ char *new_alias = NULL;
+
+ g_return_if_fail(buddy != NULL);
+
+ if ((alias != NULL) && (*alias != '\0') && g_utf8_validate(alias, -1, NULL))
+ new_alias = purple_utf8_strip_unprintables(alias);
+
+ if (!purple_strings_are_different(buddy->server_alias, new_alias)) {
+ g_free(new_alias);
+ return;
+ }
+
+ old_alias = buddy->server_alias;
+
+ if ((new_alias != NULL) && (*new_alias != '\0'))
+ buddy->server_alias = new_alias;
+ else {
+ buddy->server_alias = NULL;
+ g_free(new_alias); /* could be "\0"; */
+ }
+
+ purple_blist_schedule_save();
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode *)buddy);
+
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy->name,
+ buddy->account);
+ if (conv)
+ purple_conversation_autoset_title(conv);
+
+ purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
+ buddy, old_alias);
+ g_free(old_alias);
+}
+
+PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *name, const char *alias)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurpleBuddy *buddy;
+
+ g_return_val_if_fail(account != NULL, NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ buddy = g_new0(PurpleBuddy, 1);
+ buddy->account = account;
+ buddy->name = purple_utf8_strip_unprintables(name);
+ buddy->alias = purple_utf8_strip_unprintables(alias);
+ buddy->presence = purple_presence_new_for_buddy(buddy);
+ ((PurpleBlistNode *)buddy)->type = PURPLE_BLIST_BUDDY_NODE;
+
+ purple_presence_set_status_active(buddy->presence, "offline", TRUE);
+
+ purple_blist_node_initialize_settings((PurpleBlistNode *)buddy);
+
+ if (ops && ops->new_node)
+ ops->new_node((PurpleBlistNode *)buddy);
+
+ PURPLE_DBUS_REGISTER_POINTER(buddy, PurpleBuddy);
+ return buddy;
+}
+
+void
+purple_buddy_destroy(PurpleBuddy *buddy)
+{
+ PurplePlugin *prpl;
+ PurplePluginProtocolInfo *prpl_info;
+
+ /*
+ * Tell the owner PRPL that we're about to free the buddy so it
+ * can free proto_data
+ */
+ prpl = purple_find_prpl(purple_account_get_protocol_id(buddy->account));
+ if (prpl) {
+ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+ if (prpl_info && prpl_info->buddy_free)
+ prpl_info->buddy_free(buddy);
+ }
+
+ /* Delete the node */
+ purple_buddy_icon_unref(buddy->icon);
+ g_hash_table_destroy(buddy->node.settings);
+ purple_presence_destroy(buddy->presence);
+ g_free(buddy->name);
+ g_free(buddy->alias);
+ g_free(buddy->server_alias);
+
+ PURPLE_DBUS_UNREGISTER_POINTER(buddy);
+ g_free(buddy);
+
+ /* FIXME: Once PurpleBuddy is a GObject, timeout callbacks can
+ * g_object_ref() it when connecting the callback and
+ * g_object_unref() it in the handler. That way, it won't
+ * get freed while the timeout is pending and this line can
+ * be removed. */
+ while (g_source_remove_by_user_data((gpointer *)buddy));
+}
+
+void
+purple_buddy_set_icon(PurpleBuddy *buddy, PurpleBuddyIcon *icon)
+{
+ g_return_if_fail(buddy != NULL);
+
+ if (buddy->icon != icon)
+ {
+ purple_buddy_icon_unref(buddy->icon);
+ buddy->icon = (icon != NULL ? purple_buddy_icon_ref(icon) : NULL);
+ }
+
+ purple_signal_emit(purple_blist_get_handle(), "buddy-icon-changed", buddy);
+
+ purple_blist_update_node_icon((PurpleBlistNode*)buddy);
+}
+
+PurpleAccount *
+purple_buddy_get_account(const PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ return buddy->account;
+}
+
+const char *
+purple_buddy_get_name(const PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ return buddy->name;
+}
+
+PurpleBuddyIcon *
+purple_buddy_get_icon(const PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ return buddy->icon;
+}
+
+gpointer
+purple_buddy_get_protocol_data(const PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ return buddy->proto_data;
+}
+
+void
+purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data)
+{
+ g_return_if_fail(buddy != NULL);
+
+ buddy->proto_data = data;
+}
+
+const char *purple_buddy_get_alias_only(PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ if ((buddy->alias != NULL) && (*buddy->alias != '\0')) {
+ return buddy->alias;
+ } else if ((purple_buddy_get_server_alias(buddy) != NULL) &&
+ (*purple_buddy_get_server_alias(buddy) != '\0')) {
+
+ return purple_buddy_get_server_alias(buddy);
+ }
+
+ return NULL;
+}
+
+const char *purple_buddy_get_contact_alias(PurpleBuddy *buddy)
+{
+ PurpleContact *c;
+
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ /* Search for an alias for the buddy. In order of precedence: */
+ /* The buddy alias */
+ if (buddy->alias != NULL)
+ return buddy->alias;
+
+ /* The contact alias */
+ c = purple_buddy_get_contact(buddy);
+ if ((c != NULL) && (c->alias != NULL))
+ return c->alias;
+
+ /* The server alias */
+ if ((purple_buddy_get_server_alias(buddy)) && (*purple_buddy_get_server_alias(buddy)))
+ return purple_buddy_get_server_alias(buddy);
+
+ /* The buddy's user name (i.e. no alias) */
+ return buddy->name;
+}
+
+const char *purple_buddy_get_alias(PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ /* Search for an alias for the buddy. In order of precedence: */
+ /* The buddy alias */
+ if (buddy->alias != NULL)
+ return buddy->alias;
+
+ /* The server alias */
+ if ((purple_buddy_get_server_alias(buddy)) && (*purple_buddy_get_server_alias(buddy)))
+ return purple_buddy_get_server_alias(buddy);
+
+ /* The buddy's user name (i.e. no alias) */
+ return buddy->name;
+}
+
+const char *purple_buddy_get_local_buddy_alias(PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy, NULL);
+ return buddy->alias;
+}
+
+const char *purple_buddy_get_server_alias(PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ if ((buddy->server_alias) && (*buddy->server_alias))
+ return buddy->server_alias;
+
+ return NULL;
+}
+
+const char *purple_buddy_get_local_alias(PurpleBuddy *buddy)
+{
+ PurpleContact *c;
+
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ /* Search for an alias for the buddy. In order of precedence: */
+ /* The buddy alias */
+ if (buddy->alias != NULL)
+ return buddy->alias;
+
+ /* The contact alias */
+ c = purple_buddy_get_contact(buddy);
+ if ((c != NULL) && (c->alias != NULL))
+ return c->alias;
+
+ /* The buddy's user name (i.e. no alias) */
+ return buddy->name;
+}
+
+PurpleBuddy *purple_find_buddy_in_group(PurpleAccount *account, const char *name,
+ PurpleGroup *group)
+{
+ struct _purple_hbuddy hb;
+ PurpleBuddy *ret;
+
+ g_return_val_if_fail(purple_blist_get_list() != NULL, NULL);
+ g_return_val_if_fail(account != NULL, NULL);
+ g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
+
+ hb.name = g_strdup(purple_normalize(account, name));
+ hb.account = account;
+ hb.group = (PurpleBlistNode*)group;
+
+ ret = g_hash_table_lookup(purple_blist_get_list()->buddies, &hb);
+ g_free(hb.name);
+
+ return ret;
+}
+
+PurpleContact *purple_buddy_get_contact(PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ return PURPLE_CONTACT(PURPLE_BLIST_NODE(buddy)->parent);
+}
+
+PurplePresence *purple_buddy_get_presence(const PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+ return buddy->presence;
+}
+
+PurpleGroup *purple_buddy_get_group(PurpleBuddy *buddy)
+{
+ g_return_val_if_fail(buddy != NULL, NULL);
+
+ if (((PurpleBlistNode *)buddy)->parent == NULL)
+ return NULL;
+
+ return (PurpleGroup *)(((PurpleBlistNode*)buddy)->parent->parent);
+}
+
+xmlnode *
+buddy_to_xmlnode(PurpleBlistNode *bnode)
+{
+ xmlnode *node, *child;
+ PurpleBuddy *buddy;
+
+ buddy = (PurpleBuddy *)bnode;
+
+ node = xmlnode_new("buddy");
+ xmlnode_set_attrib(node, "account", purple_account_get_username(buddy->account));
+ xmlnode_set_attrib(node, "proto", purple_account_get_protocol_id(buddy->account));
+
+ child = xmlnode_new_child(node, "name");
+ xmlnode_insert_data(child, buddy->name, -1);
+
+ if (buddy->alias != NULL)
+ {
+ child = xmlnode_new_child(node, "alias");
+ xmlnode_insert_data(child, buddy->alias, -1);
+ }
+
+ /* Write buddy settings */
+ g_hash_table_foreach(buddy->node.settings, value_to_xmlnode, node);
+
+ return node;
+}
============================================================
--- libpurple/chat.c 3183d861ddd88cb7e861d72304bf9b2c8b294aed
+++ libpurple/chat.c 3183d861ddd88cb7e861d72304bf9b2c8b294aed
@@ -0,0 +1,307 @@
+/*
+ * purple
+ *
+ * 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
+ * source distribution.
+ *
+ * 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
+ *
+ */
+#define _PURPLE_CHAT_C
+#define _BLIST_HELPERS_
+
+#include "internal.h"
+#include "blist.h"
+#include "conversation.h"
+#include "dbus-maybe.h"
+#include "debug.h"
+#include "notify.h"
+#include "prefs.h"
+#include "privacy.h"
+#include "prpl.h"
+#include "server.h"
+#include "signals.h"
+#include "util.h"
+#include "value.h"
+#include "xmlnode.h"
+
+static void
+chat_component_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
+{
+ const char *name;
+ const char *data;
+ xmlnode *node, *child;
+
+ name = (const char *)key;
+ data = (const char *)value;
+ node = (xmlnode *)user_data;
+
+ g_return_if_fail(data != NULL);
+
+ child = xmlnode_new_child(node, "component");
+ xmlnode_set_attrib(child, "name", name);
+ xmlnode_insert_data(child, data, -1);
+}
+
+xmlnode *
+chat_to_xmlnode(PurpleBlistNode *cnode)
+{
+ xmlnode *node, *child;
+ PurpleChat *chat;
+
+ chat = (PurpleChat *)cnode;
+
+ node = xmlnode_new("chat");
+ xmlnode_set_attrib(node, "proto", purple_account_get_protocol_id(chat->account));
+ xmlnode_set_attrib(node, "account", purple_account_get_username(chat->account));
+
+ if (chat->alias != NULL)
+ {
+ child = xmlnode_new_child(node, "alias");
+ xmlnode_insert_data(child, chat->alias, -1);
+ }
+
+ /* Write chat components */
+ g_hash_table_foreach(chat->components, chat_component_to_xmlnode, node);
+
+ /* Write chat settings */
+ g_hash_table_foreach(chat->node.settings, value_to_xmlnode, node);
+
+ return node;
+}
+
+void
+parse_chat(PurpleGroup *group, xmlnode *cnode)
+{
+ PurpleChat *chat;
+ PurpleAccount *account;
+ const char *acct_name, *proto, *protocol;
+ xmlnode *x;
+ char *alias = NULL;
+ GHashTable *components;
+
+ acct_name = xmlnode_get_attrib(cnode, "account");
+ protocol = xmlnode_get_attrib(cnode, "protocol");
+ proto = xmlnode_get_attrib(cnode, "proto");
+
+ if (!acct_name || (!proto && !protocol))
+ return;
+
+ account = purple_accounts_find(acct_name, proto ? proto : protocol);
+
+ if (!account)
+ return;
+
+ if ((x = xmlnode_get_child(cnode, "alias")))
+ alias = xmlnode_get_data(x);
+
+ components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+
+ for (x = xmlnode_get_child(cnode, "component"); x; x = xmlnode_get_next_twin(x)) {
+ const char *name;
+ char *value;
+
+ name = xmlnode_get_attrib(x, "name");
+ value = xmlnode_get_data(x);
+ g_hash_table_replace(components, g_strdup(name), value);
+ }
+
+ chat = purple_chat_new(account, alias, components);
+ purple_blist_add_chat(chat, group,
+ purple_blist_get_last_child((PurpleBlistNode*)group));
+
+ for (x = xmlnode_get_child(cnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
+ parse_setting((PurpleBlistNode*)chat, x);
+ }
+
+ g_free(alias);
+}
+
+void purple_blist_alias_chat(PurpleChat *chat, const char *alias)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ char *old_alias;
+ char *new_alias = NULL;
+
+ g_return_if_fail(chat != NULL);
+
+ if ((alias != NULL) && (*alias != '\0'))
+ new_alias = purple_utf8_strip_unprintables(alias);
+
+ if (!purple_strings_are_different(chat->alias, new_alias)) {
+ g_free(new_alias);
+ return;
+ }
+
+ old_alias = chat->alias;
+
+ if ((new_alias != NULL) && (*new_alias != '\0'))
+ chat->alias = new_alias;
+ else {
+ chat->alias = NULL;
+ g_free(new_alias); /* could be "\0" */
+ }
+
+ purple_blist_schedule_save();
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode *)chat);
+
+ purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
+ chat, old_alias);
+ g_free(old_alias);
+}
+
+PurpleChat *purple_chat_new(PurpleAccount *account, const char *alias, GHashTable *components)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurpleChat *chat;
+
+ g_return_val_if_fail(account != NULL, FALSE);
+ g_return_val_if_fail(components != NULL, FALSE);
+
+ chat = g_new0(PurpleChat, 1);
+ chat->account = account;
+ if ((alias != NULL) && (*alias != '\0'))
+ chat->alias = purple_utf8_strip_unprintables(alias);
+ chat->components = components;
+ purple_blist_node_initialize_settings((PurpleBlistNode *)chat);
+ ((PurpleBlistNode *)chat)->type = PURPLE_BLIST_CHAT_NODE;
+
+ if (ops != NULL && ops->new_node != NULL)
+ ops->new_node((PurpleBlistNode *)chat);
+
+ PURPLE_DBUS_REGISTER_POINTER(chat, PurpleChat);
+ return chat;
+}
+
+void
+purple_chat_destroy(PurpleChat *chat)
+{
+ g_hash_table_destroy(chat->components);
+ g_hash_table_destroy(chat->node.settings);
+ g_free(chat->alias);
+ PURPLE_DBUS_UNREGISTER_POINTER(chat);
+ g_free(chat);
+}
+
+const char *purple_chat_get_name(PurpleChat *chat)
+{
+ char *ret = NULL;
+ PurplePlugin *prpl;
+ PurplePluginProtocolInfo *prpl_info = NULL;
+
+ g_return_val_if_fail(chat != NULL, NULL);
+
+ if ((chat->alias != NULL) && (*chat->alias != '\0'))
+ return chat->alias;
+
+ prpl = purple_find_prpl(purple_account_get_protocol_id(chat->account));
+ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+ if (prpl_info->chat_info) {
+ struct proto_chat_entry *pce;
+ GList *parts = prpl_info->chat_info(purple_account_get_connection(chat->account));
+ pce = parts->data;
+ ret = g_hash_table_lookup(chat->components, pce->identifier);
+ g_list_foreach(parts, (GFunc)g_free, NULL);
+ g_list_free(parts);
+ }
+
+ return ret;
+}
+
+PurpleChat *
+purple_blist_find_chat(PurpleAccount *account, const char *name)
+{
+ char *chat_name;
+ PurpleChat *chat;
+ PurplePlugin *prpl;
+ PurplePluginProtocolInfo *prpl_info = NULL;
+ struct proto_chat_entry *pce;
+ PurpleBlistNode *node, *group;
+ GList *parts;
+ char *normname;
+
+ g_return_val_if_fail(purple_blist_get_list() != NULL, NULL);
+ g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
+
+ if (!purple_account_is_connected(account))
+ return NULL;
+
+ prpl = purple_find_prpl(purple_account_get_protocol_id(account));
+ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+ if (prpl_info->find_blist_chat != NULL)
+ return prpl_info->find_blist_chat(account, name);
+
+ normname = g_strdup(purple_normalize(account, name));
+ for (group = purple_blist_get_list()->root; group != NULL; group = group->next) {
+ for (node = group->child; node != NULL; node = node->next) {
+ if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
+
+ chat = (PurpleChat*)node;
+
+ if (account != chat->account)
+ continue;
+
+ parts = prpl_info->chat_info(
+ purple_account_get_connection(chat->account));
+
+ pce = parts->data;
+ chat_name = g_hash_table_lookup(chat->components,
+ pce->identifier);
+ g_list_foreach(parts, (GFunc)g_free, NULL);
+ g_list_free(parts);
+
+ if (chat->account == account && chat_name != NULL &&
+ normname != NULL && !strcmp(purple_normalize(account, chat_name), normname)) {
+ g_free(normname);
+ return chat;
+ }
+ }
+ }
+ }
+
+ g_free(normname);
+ return NULL;
+}
+
+PurpleGroup *
+purple_chat_get_group(PurpleChat *chat)
+{
+ g_return_val_if_fail(chat != NULL, NULL);
+
+ return (PurpleGroup *)(((PurpleBlistNode *)chat)->parent);
+}
+
+PurpleAccount *
+purple_chat_get_account(PurpleChat *chat)
+{
+ g_return_val_if_fail(chat != NULL, NULL);
+
+ return chat->account;
+}
+
+GHashTable *
+purple_chat_get_components(PurpleChat *chat)
+{
+ g_return_val_if_fail(chat != NULL, NULL);
+
+ return chat->components;
+}
+
+
============================================================
--- libpurple/contact.c aee5a71756fb1cf9f13a88939a5bf111aceeacd3
+++ libpurple/contact.c aee5a71756fb1cf9f13a88939a5bf111aceeacd3
@@ -0,0 +1,302 @@
+/*
+ * purple
+ *
+ * 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
+ * source distribution.
+ *
+ * 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
+ *
+ */
+#define _PURPLE_CHAT_C_
+#define _BLIST_HELPERS_
+
+#include "internal.h"
+#include "blist.h"
+#include "conversation.h"
+#include "dbus-maybe.h"
+#include "debug.h"
+#include "notify.h"
+#include "prefs.h"
+#include "privacy.h"
+#include "prpl.h"
+#include "server.h"
+#include "signals.h"
+#include "util.h"
+#include "value.h"
+#include "xmlnode.h"
+
+xmlnode *
+contact_to_xmlnode(PurpleBlistNode *cnode)
+{
+ xmlnode *node, *child;
+ PurpleContact *contact;
+ PurpleBlistNode *bnode;
+
+ contact = (PurpleContact *)cnode;
+
+ node = xmlnode_new("contact");
+
+ if (contact->alias != NULL)
+ {
+ xmlnode_set_attrib(node, "alias", contact->alias);
+ }
+
+ /* Write buddies */
+ for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
+ {
+ if (!PURPLE_BLIST_NODE_SHOULD_SAVE(bnode))
+ continue;
+ if (PURPLE_BLIST_NODE_IS_BUDDY(bnode))
+ {
+ child = buddy_to_xmlnode(bnode);
+ xmlnode_insert_child(node, child);
+ }
+ }
+
+ /* Write contact settings */
+ g_hash_table_foreach(cnode->settings, value_to_xmlnode, node);
+
+ return node;
+}
+
+void
+parse_contact(PurpleGroup *group, xmlnode *cnode)
+{
+ PurpleContact *contact = purple_contact_new();
+ xmlnode *x;
+ const char *alias;
+
+ purple_blist_add_contact(contact, group,
+ purple_blist_get_last_child((PurpleBlistNode*)group));
+
+ if ((alias = xmlnode_get_attrib(cnode, "alias"))) {
+ purple_blist_alias_contact(contact, alias);
+ }
+
+ for (x = cnode->child; x; x = x->next) {
+ if (x->type != XMLNODE_TYPE_TAG)
+ continue;
+ if (purple_strequal(x->name, "buddy"))
+ parse_buddy(group, contact, x);
+ else if (purple_strequal(x->name, "setting"))
+ parse_setting((PurpleBlistNode*)contact, x);
+ }
+
+ /* if the contact is empty, don't keep it around. it causes problems */
+ if (!((PurpleBlistNode*)contact)->child)
+ purple_blist_remove_contact(contact);
+}
+
+void
+purple_contact_compute_priority_buddy(PurpleContact *contact)
+{
+ PurpleBlistNode *bnode;
+ PurpleBuddy *new_priority = NULL;
+
+ g_return_if_fail(contact != NULL);
+
+ contact->priority = NULL;
+ for (bnode = ((PurpleBlistNode*)contact)->child;
+ bnode != NULL;
+ bnode = bnode->next)
+ {
+ PurpleBuddy *buddy;
+
+ if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
+ continue;
+
+ buddy = (PurpleBuddy*)bnode;
+ if (new_priority == NULL)
+ {
+ new_priority = buddy;
+ continue;
+ }
+
+ if (purple_account_is_connected(buddy->account))
+ {
+ int cmp = 1;
+ if (purple_account_is_connected(new_priority->account))
+ cmp = purple_presence_compare(purple_buddy_get_presence(new_priority),
+ purple_buddy_get_presence(buddy));
+
+ if (cmp > 0 || (cmp == 0 &&
+ purple_prefs_get_bool("/purple/contact/last_match")))
+ {
+ new_priority = buddy;
+ }
+ }
+ }
+
+ contact->priority = new_priority;
+ contact->priority_valid = TRUE;
+}
+
+/*****************************************************************************
+ * Public API functions *
+ *****************************************************************************/
+
+void purple_blist_alias_contact(PurpleContact *contact, const char *alias)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurpleConversation *conv;
+ PurpleBlistNode *bnode;
+ char *old_alias;
+ char *new_alias = NULL;
+
+ g_return_if_fail(contact != NULL);
+
+ if ((alias != NULL) && (*alias != '\0'))
+ new_alias = purple_utf8_strip_unprintables(alias);
+
+ if (!purple_strings_are_different(contact->alias, new_alias)) {
+ g_free(new_alias);
+ return;
+ }
+
+ old_alias = contact->alias;
+
+ if ((new_alias != NULL) && (*new_alias != '\0'))
+ contact->alias = new_alias;
+ else {
+ contact->alias = NULL;
+ g_free(new_alias); /* could be "\0" */
+ }
+
+ purple_blist_schedule_save();
+
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode *)contact);
+
+ for(bnode = ((PurpleBlistNode *)contact)->child; bnode != NULL; bnode = bnode->next)
+ {
+ PurpleBuddy *buddy = (PurpleBuddy *)bnode;
+
+ conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy->name,
+ buddy->account);
+ if (conv)
+ purple_conversation_autoset_title(conv);
+ }
+
+ purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
+ contact, old_alias);
+ g_free(old_alias);
+}
+
+PurpleContact *purple_contact_new()
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+
+ PurpleContact *contact = g_new0(PurpleContact, 1);
+ contact->totalsize = 0;
+ contact->currentsize = 0;
+ contact->online = 0;
+ purple_blist_node_initialize_settings((PurpleBlistNode *)contact);
+ ((PurpleBlistNode *)contact)->type = PURPLE_BLIST_CONTACT_NODE;
+
+ if (ops && ops->new_node)
+ ops->new_node((PurpleBlistNode *)contact);
+
+ PURPLE_DBUS_REGISTER_POINTER(contact, PurpleContact);
+ return contact;
+}
+
+void
+purple_contact_destroy(PurpleContact *contact)
+{
+ g_hash_table_destroy(contact->node.settings);
+ g_free(contact->alias);
+ PURPLE_DBUS_UNREGISTER_POINTER(contact);
+ g_free(contact);
+}
+
+void purple_contact_set_alias(PurpleContact *contact, const char *alias)
+{
+ purple_blist_alias_contact(contact,alias);
+}
+
+const char *purple_contact_get_alias(PurpleContact* contact)
+{
+ g_return_val_if_fail(contact != NULL, NULL);
+
+ if (contact->alias)
+ return contact->alias;
+
+ return purple_buddy_get_alias(purple_contact_get_priority_buddy(contact));
+}
+
+gboolean purple_contact_on_account(PurpleContact *c, PurpleAccount *account)
+{
+ PurpleBlistNode *bnode, *cnode = (PurpleBlistNode *) c;
+
+ g_return_val_if_fail(c != NULL, FALSE);
+ g_return_val_if_fail(account != NULL, FALSE);
+
+ for (bnode = cnode->child; bnode; bnode = bnode->next) {
+ PurpleBuddy *buddy;
+
+ if (! PURPLE_BLIST_NODE_IS_BUDDY(bnode))
+ continue;
+
+ buddy = (PurpleBuddy *)bnode;
+ if (buddy->account == account)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void purple_contact_invalidate_priority_buddy(PurpleContact *contact)
+{
+ g_return_if_fail(contact != NULL);
+
+ contact->priority_valid = FALSE;
+}
+
+PurpleGroup *purple_group_new(const char *name)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurpleGroup *group;
+
+ g_return_val_if_fail(name != NULL, NULL);
+ g_return_val_if_fail(*name != '\0', NULL);
+
+ group = purple_find_group(name);
+ if (group != NULL)
+ return group;
+
+ group = g_new0(PurpleGroup, 1);
+ group->name = purple_utf8_strip_unprintables(name);
+ group->totalsize = 0;
+ group->currentsize = 0;
+ group->online = 0;
+ purple_blist_node_initialize_settings((PurpleBlistNode *)group);
+ ((PurpleBlistNode *)group)->type = PURPLE_BLIST_GROUP_NODE;
+
+ if (ops && ops->new_node)
+ ops->new_node((PurpleBlistNode *)group);
+
+ PURPLE_DBUS_REGISTER_POINTER(group, PurpleGroup);
+ return group;
+}
+
+PurpleBuddy *purple_contact_get_priority_buddy(PurpleContact *contact)
+{
+ g_return_val_if_fail(contact != NULL, NULL);
+
+ if (!contact->priority_valid)
+ purple_contact_compute_priority_buddy(contact);
+
+ return contact->priority;
+}
============================================================
--- libpurple/group.c a00a480ba06e038f085790a88d89dacfb0d333fe
+++ libpurple/group.c a00a480ba06e038f085790a88d89dacfb0d333fe
@@ -0,0 +1,284 @@
+/*
+ * purple
+ *
+ * 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
+ * source distribution.
+ *
+ * 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
+ *
+ */
+#define _PURPLE_GROUP_C_
+#define _BLIST_HELPERS_
+
+#include "internal.h"
+#include "blist.h"
+#include "conversation.h"
+#include "dbus-maybe.h"
+#include "debug.h"
+#include "notify.h"
+#include "prefs.h"
+#include "privacy.h"
+#include "prpl.h"
+#include "server.h"
+#include "signals.h"
+#include "util.h"
+#include "value.h"
+#include "xmlnode.h"
+
+xmlnode *
+group_to_xmlnode(PurpleBlistNode *gnode)
+{
+ xmlnode *node, *child;
+ PurpleGroup *group;
+ PurpleBlistNode *cnode;
+
+ group = (PurpleGroup *)gnode;
+
+ node = xmlnode_new("group");
+ xmlnode_set_attrib(node, "name", group->name);
+
+ /* Write settings */
+ g_hash_table_foreach(group->node.settings, value_to_xmlnode, node);
+
+ /* Write contacts and chats */
+ for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
+ {
+ if (!PURPLE_BLIST_NODE_SHOULD_SAVE(cnode))
+ continue;
+ if (PURPLE_BLIST_NODE_IS_CONTACT(cnode))
+ {
+ child = contact_to_xmlnode(cnode);
+ xmlnode_insert_child(node, child);
+ }
+ else if (PURPLE_BLIST_NODE_IS_CHAT(cnode))
+ {
+ child = chat_to_xmlnode(cnode);
+ xmlnode_insert_child(node, child);
+ }
+ }
+
+ return node;
+}
+
+void
+parse_group(xmlnode *groupnode)
+{
+ const char *name = xmlnode_get_attrib(groupnode, "name");
+ PurpleGroup *group;
+ xmlnode *cnode;
+
+ if (!name)
+ name = _("Buddies");
+
+ group = purple_group_new(name);
+ purple_blist_add_group(group,
+ purple_blist_get_last_sibling(purple_blist_get_list()->root));
+
+ for (cnode = groupnode->child; cnode; cnode = cnode->next) {
+ if (cnode->type != XMLNODE_TYPE_TAG)
+ continue;
+ if (purple_strequal(cnode->name, "setting"))
+ parse_setting((PurpleBlistNode*)group, cnode);
+ else if (purple_strequal(cnode->name, "contact") ||
+ purple_strequal(cnode->name, "person"))
+ parse_contact(group, cnode);
+ else if (purple_strequal(cnode->name, "chat"))
+ parse_chat(group, cnode);
+ }
+}
+
+/*
+ * TODO: If merging, prompt the user if they want to merge.
+ */
+void purple_blist_rename_group(PurpleGroup *source, const char *name)
+{
+ PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
+ PurpleGroup *dest;
+ gchar *old_name;
+ gchar *new_name;
+ GList *moved_buddies = NULL;
+ GSList *accts;
+
+ g_return_if_fail(source != NULL);
+ g_return_if_fail(name != NULL);
+
+ new_name = purple_utf8_strip_unprintables(name);
+
+ if (*new_name == '\0' || purple_strequal(new_name, source->name)) {
+ g_free(new_name);
+ return;
+ }
+
+ dest = purple_find_group(new_name);
+ if (dest != NULL && purple_utf8_strcasecmp(source->name, dest->name) != 0) {
+ /* We're merging two groups */
+ PurpleBlistNode *prev, *child, *next;
+
+ prev = purple_blist_get_last_child((PurpleBlistNode*)dest);
+ child = ((PurpleBlistNode*)source)->child;
+
+ /*
+ * TODO: This seems like a dumb way to do this... why not just
+ * append all children from the old group to the end of the new
+ * one? PRPLs might be expecting to receive an add_buddy() for
+ * each moved buddy...
+ */
+ while (child)
+ {
+ next = child->next;
+ if (PURPLE_BLIST_NODE_IS_CONTACT(child)) {
+ PurpleBlistNode *bnode;
+ purple_blist_add_contact((PurpleContact *)child, dest, prev);
+ for (bnode = child->child; bnode != NULL; bnode = bnode->next) {
+ purple_blist_add_buddy((PurpleBuddy *)bnode, (PurpleContact *)child,
+ NULL, bnode->prev);
+ moved_buddies = g_list_append(moved_buddies, bnode);
+ }
+ prev = child;
+ } else if (PURPLE_BLIST_NODE_IS_CHAT(child)) {
+ purple_blist_add_chat((PurpleChat *)child, dest, prev);
+ prev = child;
+ } else {
+ purple_debug(PURPLE_DEBUG_ERROR, "blist",
+ "Unknown child type in group %s\n", source->name);
+ }
+ child = next;
+ }
+
+ /* Make a copy of the old group name and then delete the old group */
+ old_name = g_strdup(source->name);
+ purple_blist_remove_group(source);
+ source = dest;
+ g_free(new_name);
+ } else {
+ /* A simple rename */
+ PurpleBlistNode *cnode, *bnode;
+
+ /* Build a GList of all buddies in this group */
+ for (cnode = ((PurpleBlistNode *)source)->child; cnode != NULL; cnode = cnode->next) {
+ if (PURPLE_BLIST_NODE_IS_CONTACT(cnode))
+ for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
+ moved_buddies = g_list_append(moved_buddies, bnode);
+ }
+
+ old_name = source->name;
+ source->name = new_name;
+ }
+
+ /* Save our changes */
+ purple_blist_schedule_save();
+
+ /* Update the UI */
+ if (ops && ops->update)
+ ops->update(purple_blist_get_list(), (PurpleBlistNode*)source);
+
+ /* Notify all PRPLs */
+ /* TODO: Is this condition needed? Seems like it would always be TRUE */
+ if(old_name && !purple_strequal(source->name, old_name)) {
+ for (accts = purple_group_get_accounts(source); accts; accts = g_slist_remove(accts, accts->data)) {
+ PurpleAccount *account = accts->data;
+ PurpleConnection *gc = NULL;
+ PurplePlugin *prpl = NULL;
+ PurplePluginProtocolInfo *prpl_info = NULL;
+ GList *l = NULL, *buddies = NULL;
+
+ gc = purple_account_get_connection(account);
+
+ if(gc)
+ prpl = purple_connection_get_prpl(gc);
+
+ if(gc && prpl)
+ prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
+
+ if(!prpl_info)
+ continue;
+
+ for(l = moved_buddies; l; l = l->next) {
+ PurpleBuddy *buddy = (PurpleBuddy *)l->data;
+
+ if(buddy && buddy->account == account)
+ buddies = g_list_append(buddies, (PurpleBlistNode *)buddy);
+ }
+
+ if(prpl_info->rename_group) {
+ prpl_info->rename_group(gc, old_name, source, buddies);
+ } else {
+ GList *cur, *groups = NULL;
+
+ /* Make a list of what the groups each buddy is in */
+ for(cur = buddies; cur; cur = cur->next) {
+ PurpleBlistNode *node = (PurpleBlistNode *)cur->data;
+ groups = g_list_prepend(groups, node->parent->parent);
+ }
+
+ purple_account_remove_buddies(account, buddies, groups);
+ g_list_free(groups);
+ purple_account_add_buddies(account, buddies);
+ }
+
+ g_list_free(buddies);
+ }
+ }
+ g_list_free(moved_buddies);
+ g_free(old_name);
+}
+
+void
+purple_group_destroy(PurpleGroup *group)
+{
+ g_hash_table_destroy(group->node.settings);
+ g_free(group->name);
+ PURPLE_DBUS_UNREGISTER_POINTER(group);
+ g_free(group);
+}
+
+PurpleGroup *purple_find_group(const char *name)
+{
+ PurpleBlistNode *node;
+
+ g_return_val_if_fail(purple_blist_get_list() != NULL, NULL);
+ g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
+
+ for (node = purple_blist_get_list()->root; node != NULL; node = node->next) {
+ if (!purple_utf8_strcasecmp(((PurpleGroup *)node)->name, name))
+ return (PurpleGroup *)node;
+ }
+
+ return NULL;
+}
+
+const char *purple_group_get_name(PurpleGroup *group)
+{
+ g_return_val_if_fail(group != NULL, NULL);
+
+ return group->name;
+}
+
+int purple_blist_get_group_size(PurpleGroup *group, gboolean offline)
+{
+ if (!group)
+ return 0;
+
+ return offline ? group->totalsize : group->currentsize;
+}
+
+int purple_blist_get_group_online_count(PurpleGroup *group)
+{
+ if (!group)
+ return 0;
+
+ return group->online;
+}
============================================================
--- libpurple/Makefile.am a056a5348cd7d3350a919a8f3e8e87b7ad5df858
+++ libpurple/Makefile.am 8185e184741f4727c96ec17e30e3abe6fe35f3fe
@@ -38,13 +38,17 @@ purple_coresources = \
accountmanager.c \
accountopt.c \
blist.c \
+ blist-node.c \
+ buddy.c \
buddyicon.c \
certificate.c \
+ chat.c \
cipher.c \
circbuffer.c \
cmds.c \
connection.c \
conversation.c \
+ contact.c \
core.c \
debug.c \
descipher.c \
@@ -52,6 +56,7 @@ purple_coresources = \
desktopitem.c \
eventloop.c \
ft.c \
+ group.c \
hmaccipher.c \
idle.c \
imgstore.c \
============================================================
--- libpurple/blist.c e38e665fd6379dc890709cd58b31f4741cc51855
+++ libpurple/blist.c 334e745de44806a8c54287ca85b1e06f4f72ca0b
@@ -21,6 +21,7 @@
*
*/
#define _PURPLE_BLIST_C_
+#define _BLIST_HELPERS_
#include "internal.h"
#include "blist.h"
@@ -55,34 +56,6 @@ static gboolean blist_loaded = FAL
* Private utility functions *
*********************************************************************/
-static PurpleBlistNode *purple_blist_get_last_sibling(PurpleBlistNode *node)
-{
- PurpleBlistNode *n = node;
- if (!n)
- return NULL;
- while (n->next)
- n = n->next;
- return n;
-}
-
-static PurpleBlistNode *purple_blist_get_last_child(PurpleBlistNode *node)
-{
- if (!node)
- return NULL;
- return purple_blist_get_last_sibling(node->child);
-}
-
-struct _list_account_buddies {
- GSList *list;
- PurpleAccount *account;
-};
-
-struct _purple_hbuddy {
- char *name;
- PurpleAccount *account;
- PurpleBlistNode *group;
-};
-
static guint _purple_blist_hbuddy_hash(struct _purple_hbuddy *hb)
{
return g_str_hash(hb->name);
@@ -114,12 +87,35 @@ purple_blist_buddies_cache_remove_accoun
g_hash_table_remove(buddies_cache, account);
}
+PurpleBuddyList*
+purple_blist_get_list(void)
+{
+ return purplebuddylist;
+}
+GHashTable*
+purple_blist_get_buddies_cache(void)
+{
+ return buddies_cache;
+}
+
+guint
+purple_blist_get_save_timer(void)
+{
+ return save_timer;
+}
+
+gboolean
+purple_blist_get_blist_loaded(void)
+{
+ return blist_loaded;
+}
+
/*********************************************************************
* Writing to disk *
*********************************************************************/
-static void
+void
value_to_xmlnode(gpointer key, gpointer hvalue, gpointer user_data)
{
const char *name;
@@ -162,148 +158,7 @@ value_to_xmlnode(gpointer key, gpointer
}
}
-static void
-chat_component_to_xmlnode(gpointer key, gpointer value, gpointer user_data)
-{
- const char *name;
- const char *data;
- xmlnode *node, *child;
-
- name = (const char *)key;
- data = (const char *)value;
- node = (xmlnode *)user_data;
-
- g_return_if_fail(data != NULL);
-
- child = xmlnode_new_child(node, "component");
- xmlnode_set_attrib(child, "name", name);
- xmlnode_insert_data(child, data, -1);
-}
-
static xmlnode *
-buddy_to_xmlnode(PurpleBlistNode *bnode)
-{
- xmlnode *node, *child;
- PurpleBuddy *buddy;
-
- buddy = (PurpleBuddy *)bnode;
-
- node = xmlnode_new("buddy");
- xmlnode_set_attrib(node, "account", purple_account_get_username(buddy->account));
- xmlnode_set_attrib(node, "proto", purple_account_get_protocol_id(buddy->account));
-
- child = xmlnode_new_child(node, "name");
- xmlnode_insert_data(child, buddy->name, -1);
-
- if (buddy->alias != NULL)
- {
- child = xmlnode_new_child(node, "alias");
- xmlnode_insert_data(child, buddy->alias, -1);
- }
-
- /* Write buddy settings */
- g_hash_table_foreach(buddy->node.settings, value_to_xmlnode, node);
-
- return node;
-}
-
-static xmlnode *
-contact_to_xmlnode(PurpleBlistNode *cnode)
-{
- xmlnode *node, *child;
- PurpleContact *contact;
- PurpleBlistNode *bnode;
-
- contact = (PurpleContact *)cnode;
-
- node = xmlnode_new("contact");
-
- if (contact->alias != NULL)
- {
- xmlnode_set_attrib(node, "alias", contact->alias);
- }
-
- /* Write buddies */
- for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
- {
- if (!PURPLE_BLIST_NODE_SHOULD_SAVE(bnode))
- continue;
- if (PURPLE_BLIST_NODE_IS_BUDDY(bnode))
- {
- child = buddy_to_xmlnode(bnode);
- xmlnode_insert_child(node, child);
- }
- }
-
- /* Write contact settings */
- g_hash_table_foreach(cnode->settings, value_to_xmlnode, node);
-
- return node;
-}
-
-static xmlnode *
-chat_to_xmlnode(PurpleBlistNode *cnode)
-{
- xmlnode *node, *child;
- PurpleChat *chat;
-
- chat = (PurpleChat *)cnode;
-
- node = xmlnode_new("chat");
- xmlnode_set_attrib(node, "proto", purple_account_get_protocol_id(chat->account));
- xmlnode_set_attrib(node, "account", purple_account_get_username(chat->account));
-
- if (chat->alias != NULL)
- {
- child = xmlnode_new_child(node, "alias");
- xmlnode_insert_data(child, chat->alias, -1);
- }
-
- /* Write chat components */
- g_hash_table_foreach(chat->components, chat_component_to_xmlnode, node);
-
- /* Write chat settings */
- g_hash_table_foreach(chat->node.settings, value_to_xmlnode, node);
-
- return node;
-}
-
-static xmlnode *
-group_to_xmlnode(PurpleBlistNode *gnode)
-{
- xmlnode *node, *child;
- PurpleGroup *group;
- PurpleBlistNode *cnode;
-
- group = (PurpleGroup *)gnode;
-
- node = xmlnode_new("group");
- xmlnode_set_attrib(node, "name", group->name);
-
- /* Write settings */
- g_hash_table_foreach(group->node.settings, value_to_xmlnode, node);
-
- /* Write contacts and chats */
- for (cnode = gnode->child; cnode != NULL; cnode = cnode->next)
- {
- if (!PURPLE_BLIST_NODE_SHOULD_SAVE(cnode))
- continue;
- if (PURPLE_BLIST_NODE_IS_CONTACT(cnode))
- {
- child = contact_to_xmlnode(cnode);
- xmlnode_insert_child(node, child);
- }
- else if (PURPLE_BLIST_NODE_IS_CHAT(cnode))
- {
- child = chat_to_xmlnode(cnode);
- xmlnode_insert_child(node, child);
- }
- }
-
- return node;
-}
-
-static xmlnode *
accountprivacy_to_xmlnode(PurpleAccount *account)
{
xmlnode *node, *child;
@@ -405,172 +260,6 @@ purple_blist_schedule_save()
* Reading from disk *
*********************************************************************/
-static void
-parse_setting(PurpleBlistNode *node, xmlnode *setting)
-{
- const char *name = xmlnode_get_attrib(setting, "name");
- const char *type = xmlnode_get_attrib(setting, "type");
- char *value = xmlnode_get_data(setting);
-
- if (!value)
- return;
-
- if (!type || purple_strequal(type, "string"))
- purple_blist_node_set_string(node, name, value);
- else if (purple_strequal(type, "bool"))
- purple_blist_node_set_bool(node, name, atoi(value));
- else if (purple_strequal(type, "int"))
- purple_blist_node_set_int(node, name, atoi(value));
-
- g_free(value);
-}
-
-static void
-parse_buddy(PurpleGroup *group, PurpleContact *contact, xmlnode *bnode)
-{
- PurpleAccount *account;
- PurpleBuddy *buddy;
- char *name = NULL, *alias = NULL;
- const char *acct_name, *proto, *protocol;
- xmlnode *x;
-
- acct_name = xmlnode_get_attrib(bnode, "account");
- protocol = xmlnode_get_attrib(bnode, "protocol");
- protocol = _purple_oscar_convert(acct_name, protocol); /* XXX: Remove */
- proto = xmlnode_get_attrib(bnode, "proto");
- proto = _purple_oscar_convert(acct_name, proto); /* XXX: Remove */
-
- if (!acct_name || (!proto && !protocol))
- return;
-
- account = purple_accounts_find(acct_name, proto ? proto : protocol);
-
- if (!account)
- return;
-
- if ((x = xmlnode_get_child(bnode, "name")))
- name = xmlnode_get_data(x);
-
- if (!name)
- return;
-
- if ((x = xmlnode_get_child(bnode, "alias")))
- alias = xmlnode_get_data(x);
-
- buddy = purple_buddy_new(account, name, alias);
- purple_blist_add_buddy(buddy, contact, group,
- purple_blist_get_last_child((PurpleBlistNode*)contact));
-
- for (x = xmlnode_get_child(bnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
- parse_setting((PurpleBlistNode*)buddy, x);
- }
-
- g_free(name);
- g_free(alias);
-}
-
-static void
-parse_contact(PurpleGroup *group, xmlnode *cnode)
-{
- PurpleContact *contact = purple_contact_new();
- xmlnode *x;
- const char *alias;
-
- purple_blist_add_contact(contact, group,
- purple_blist_get_last_child((PurpleBlistNode*)group));
-
- if ((alias = xmlnode_get_attrib(cnode, "alias"))) {
- purple_blist_alias_contact(contact, alias);
- }
-
- for (x = cnode->child; x; x = x->next) {
- if (x->type != XMLNODE_TYPE_TAG)
- continue;
- if (purple_strequal(x->name, "buddy"))
- parse_buddy(group, contact, x);
- else if (purple_strequal(x->name, "setting"))
- parse_setting((PurpleBlistNode*)contact, x);
- }
-
- /* if the contact is empty, don't keep it around. it causes problems */
- if (!((PurpleBlistNode*)contact)->child)
- purple_blist_remove_contact(contact);
-}
-
-static void
-parse_chat(PurpleGroup *group, xmlnode *cnode)
-{
- PurpleChat *chat;
- PurpleAccount *account;
- const char *acct_name, *proto, *protocol;
- xmlnode *x;
- char *alias = NULL;
- GHashTable *components;
-
- acct_name = xmlnode_get_attrib(cnode, "account");
- protocol = xmlnode_get_attrib(cnode, "protocol");
- proto = xmlnode_get_attrib(cnode, "proto");
-
- if (!acct_name || (!proto && !protocol))
- return;
-
- account = purple_accounts_find(acct_name, proto ? proto : protocol);
-
- if (!account)
- return;
-
- if ((x = xmlnode_get_child(cnode, "alias")))
- alias = xmlnode_get_data(x);
-
- components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
-
- for (x = xmlnode_get_child(cnode, "component"); x; x = xmlnode_get_next_twin(x)) {
- const char *name;
- char *value;
-
- name = xmlnode_get_attrib(x, "name");
- value = xmlnode_get_data(x);
- g_hash_table_replace(components, g_strdup(name), value);
- }
-
- chat = purple_chat_new(account, alias, components);
- purple_blist_add_chat(chat, group,
- purple_blist_get_last_child((PurpleBlistNode*)group));
-
- for (x = xmlnode_get_child(cnode, "setting"); x; x = xmlnode_get_next_twin(x)) {
- parse_setting((PurpleBlistNode*)chat, x);
- }
-
- g_free(alias);
-}
-
-static void
-parse_group(xmlnode *groupnode)
-{
- const char *name = xmlnode_get_attrib(groupnode, "name");
- PurpleGroup *group;
- xmlnode *cnode;
-
- if (!name)
- name = _("Buddies");
-
- group = purple_group_new(name);
- purple_blist_add_group(group,
- purple_blist_get_last_sibling(purplebuddylist->root));
-
- for (cnode = groupnode->child; cnode; cnode = cnode->next) {
- if (cnode->type != XMLNODE_TYPE_TAG)
- continue;
- if (purple_strequal(cnode->name, "setting"))
- parse_setting((PurpleBlistNode*)group, cnode);
- else if (purple_strequal(cnode->name, "contact") ||
- purple_strequal(cnode->name, "person"))
- parse_contact(group, cnode);
- else if (purple_strequal(cnode->name, "chat"))
- parse_chat(group, cnode);
- }
-}
-
/* TODO: Make static and rename to load_blist */
void
purple_blist_load()
@@ -647,51 +336,7 @@ purple_blist_load()
* Stuff *
*********************************************************************/
-static void
-purple_contact_compute_priority_buddy(PurpleContact *contact)
-{
- PurpleBlistNode *bnode;
- PurpleBuddy *new_priority = NULL;
- g_return_if_fail(contact != NULL);
-
- contact->priority = NULL;
- for (bnode = ((PurpleBlistNode*)contact)->child;
- bnode != NULL;
- bnode = bnode->next)
- {
- PurpleBuddy *buddy;
-
- if (!PURPLE_BLIST_NODE_IS_BUDDY(bnode))
- continue;
-
- buddy = (PurpleBuddy*)bnode;
- if (new_priority == NULL)
- {
- new_priority = buddy;
- continue;
- }
-
- if (purple_account_is_connected(buddy->account))
- {
- int cmp = 1;
- if (purple_account_is_connected(new_priority->account))
- cmp = purple_presence_compare(purple_buddy_get_presence(new_priority),
- purple_buddy_get_presence(buddy));
-
- if (cmp > 0 || (cmp == 0 &&
- purple_prefs_get_bool("/purple/contact/last_match")))
- {
- new_priority = buddy;
- }
- }
- }
-
- contact->priority = new_priority;
- contact->priority_valid = TRUE;
-}
-
-
/*****************************************************************************
* Public API functions *
*****************************************************************************/
@@ -741,25 +386,6 @@ purple_blist_get_root()
return purplebuddylist ? purplebuddylist->root : NULL;
}
-static void
-append_buddy(gpointer key, gpointer value, gpointer user_data)
-{
- GSList **list = user_data;
- *list = g_slist_prepend(*list, value);
-}
-
-GSList *
-purple_blist_get_buddies()
-{
- GSList *buddies = NULL;
-
- if (!purplebuddylist)
- return NULL;
-
- g_hash_table_foreach(purplebuddylist->buddies, append_buddy, &buddies);
- return buddies;
-}
-
void *
purple_blist_get_ui_data()
{
@@ -798,984 +424,15 @@ void purple_blist_set_visible(gboolean s
ops->set_visible(purplebuddylist, show);
}
-static PurpleBlistNode *get_next_node(PurpleBlistNode *node, gboolean godeep)
-{
- if (node == NULL)
- return NULL;
- if (godeep && node->child)
- return node->child;
- if (node->next)
- return node->next;
-
- return get_next_node(node->parent, FALSE);
-}
-
-PurpleBlistNode *purple_blist_node_next(PurpleBlistNode *node, gboolean offline)
-{
- PurpleBlistNode *ret = node;
-
- if (offline)
- return get_next_node(ret, TRUE);
- do
- {
- ret = get_next_node(ret, TRUE);
- } while (ret && PURPLE_BLIST_NODE_IS_BUDDY(ret) &&
- !purple_account_is_connected(purple_buddy_get_account((PurpleBuddy *)ret)));
-
- return ret;
-}
-
-PurpleBlistNode *purple_blist_node_get_parent(PurpleBlistNode *node)
-{
- return node ? node->parent : NULL;
-}
-
-PurpleBlistNode *purple_blist_node_get_first_child(PurpleBlistNode *node)
-{
- return node ? node->child : NULL;
-}
-
-PurpleBlistNode *purple_blist_node_get_sibling_next(PurpleBlistNode *node)
-{
- return node? node->next : NULL;
-}
-
-PurpleBlistNode *purple_blist_node_get_sibling_prev(PurpleBlistNode *node)
-{
- return node? node->prev : NULL;
-}
-
-void *
-purple_blist_node_get_ui_data(const PurpleBlistNode *node)
-{
- g_return_val_if_fail(node, NULL);
-
- return node->ui_data;
-}
-
-void
-purple_blist_node_set_ui_data(PurpleBlistNode *node, void *ui_data) {
- g_return_if_fail(node);
-
- node->ui_data = ui_data;
-}
-
-void
-purple_blist_update_buddy_status(PurpleBuddy *buddy, PurpleStatus *old_status)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurplePresence *presence;
- PurpleStatus *status;
- PurpleBlistNode *cnode;
-
- g_return_if_fail(buddy != NULL);
-
- presence = purple_buddy_get_presence(buddy);
- status = purple_presence_get_active_status(presence);
-
- purple_debug_info("blist", "Updating buddy status for %s (%s)\n",
- buddy->name, purple_account_get_protocol_name(buddy->account));
-
- if (purple_status_is_online(status) &&
- !purple_status_is_online(old_status)) {
-
- purple_signal_emit(purple_blist_get_handle(), "buddy-signed-on", buddy);
-
- cnode = buddy->node.parent;
- if (++(PURPLE_CONTACT(cnode)->online) == 1)
- PURPLE_GROUP(cnode->parent)->online++;
- } else if (!purple_status_is_online(status) &&
- purple_status_is_online(old_status)) {
-
- purple_blist_node_set_int(&buddy->node, "last_seen", time(NULL));
- purple_signal_emit(purple_blist_get_handle(), "buddy-signed-off", buddy);
-
- cnode = buddy->node.parent;
- if (--(PURPLE_CONTACT(cnode)->online) == 0)
- PURPLE_GROUP(cnode->parent)->online--;
- } else {
- purple_signal_emit(purple_blist_get_handle(),
- "buddy-status-changed", buddy, old_status,
- status);
- }
-
- /*
- * This function used to only call the following two functions if one of
- * the above signals had been triggered, but that's not good, because
- * if someone's away message changes and they don't go from away to back
- * to away then no signal is triggered.
- *
- * It's a safe assumption that SOMETHING called this function. PROBABLY
- * because something, somewhere changed. Calling the stuff below
- * certainly won't hurt anything. Unless you're on a K6-2 300.
- */
- purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode *)buddy);
-}
-
-void
-purple_blist_update_node_icon(PurpleBlistNode *node)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
-
- g_return_if_fail(node != NULL);
-
- if (ops && ops->update)
- ops->update(purplebuddylist, node);
-}
-
-void
-purple_blist_update_buddy_icon(PurpleBuddy *buddy)
-{
- purple_blist_update_node_icon((PurpleBlistNode *)buddy);
-}
-
-/*
- * TODO: Maybe remove the call to this from server.c and call it
- * from oscar.c and toc.c instead?
- */
-void purple_blist_rename_buddy(PurpleBuddy *buddy, const char *name)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- struct _purple_hbuddy *hb, *hb2;
- GHashTable *account_buddies;
-
- g_return_if_fail(buddy != NULL);
-
- hb = g_new(struct _purple_hbuddy, 1);
- hb->name = g_strdup(purple_normalize(buddy->account, buddy->name));
- hb->account = buddy->account;
- hb->group = ((PurpleBlistNode *)buddy)->parent->parent;
- g_hash_table_remove(purplebuddylist->buddies, hb);
-
- account_buddies = g_hash_table_lookup(buddies_cache, buddy->account);
- g_hash_table_remove(account_buddies, hb);
-
- g_free(hb->name);
- hb->name = g_strdup(purple_normalize(buddy->account, name));
- g_hash_table_replace(purplebuddylist->buddies, hb, buddy);
-
- hb2 = g_new(struct _purple_hbuddy, 1);
- hb2->name = g_strdup(hb->name);
- hb2->account = buddy->account;
- hb2->group = ((PurpleBlistNode *)buddy)->parent->parent;
-
- g_hash_table_replace(account_buddies, hb2, buddy);
-
- g_free(buddy->name);
- buddy->name = g_strdup(name);
-
- purple_blist_schedule_save();
-
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode *)buddy);
-}
-
-static gboolean
+gboolean
purple_strings_are_different(const char *one, const char *two)
{
return !((one && two && g_utf8_collate(one, two) == 0) ||
((one == NULL || *one == '\0') && (two == NULL || *two == '\0')));
}
-void purple_blist_alias_contact(PurpleContact *contact, const char *alias)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurpleConversation *conv;
- PurpleBlistNode *bnode;
- char *old_alias;
- char *new_alias = NULL;
-
- g_return_if_fail(contact != NULL);
-
- if ((alias != NULL) && (*alias != '\0'))
- new_alias = purple_utf8_strip_unprintables(alias);
-
- if (!purple_strings_are_different(contact->alias, new_alias)) {
- g_free(new_alias);
- return;
- }
-
- old_alias = contact->alias;
-
- if ((new_alias != NULL) && (*new_alias != '\0'))
- contact->alias = new_alias;
- else {
- contact->alias = NULL;
- g_free(new_alias); /* could be "\0" */
- }
-
- purple_blist_schedule_save();
-
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode *)contact);
-
- for(bnode = ((PurpleBlistNode *)contact)->child; bnode != NULL; bnode = bnode->next)
- {
- PurpleBuddy *buddy = (PurpleBuddy *)bnode;
-
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy->name,
- buddy->account);
- if (conv)
- purple_conversation_autoset_title(conv);
- }
-
- purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
- contact, old_alias);
- g_free(old_alias);
-}
-
-void purple_blist_alias_chat(PurpleChat *chat, const char *alias)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- char *old_alias;
- char *new_alias = NULL;
-
- g_return_if_fail(chat != NULL);
-
- if ((alias != NULL) && (*alias != '\0'))
- new_alias = purple_utf8_strip_unprintables(alias);
-
- if (!purple_strings_are_different(chat->alias, new_alias)) {
- g_free(new_alias);
- return;
- }
-
- old_alias = chat->alias;
-
- if ((new_alias != NULL) && (*new_alias != '\0'))
- chat->alias = new_alias;
- else {
- chat->alias = NULL;
- g_free(new_alias); /* could be "\0" */
- }
-
- purple_blist_schedule_save();
-
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode *)chat);
-
- purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
- chat, old_alias);
- g_free(old_alias);
-}
-
-void purple_blist_alias_buddy(PurpleBuddy *buddy, const char *alias)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurpleConversation *conv;
- char *old_alias;
- char *new_alias = NULL;
-
- g_return_if_fail(buddy != NULL);
-
- if ((alias != NULL) && (*alias != '\0'))
- new_alias = purple_utf8_strip_unprintables(alias);
-
- if (!purple_strings_are_different(buddy->alias, new_alias)) {
- g_free(new_alias);
- return;
- }
-
- old_alias = buddy->alias;
-
- if ((new_alias != NULL) && (*new_alias != '\0'))
- buddy->alias = g_strdup(alias);
- else {
- buddy->alias = NULL;
- g_free(new_alias); /* could be "\0" */
- }
-
- purple_blist_schedule_save();
-
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode *)buddy);
-
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy->name,
- buddy->account);
- if (conv)
- purple_conversation_autoset_title(conv);
-
- purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
- buddy, old_alias);
- g_free(old_alias);
-}
-
-void purple_blist_server_alias_buddy(PurpleBuddy *buddy, const char *alias)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurpleConversation *conv;
- char *old_alias;
- char *new_alias = NULL;
-
- g_return_if_fail(buddy != NULL);
-
- if ((alias != NULL) && (*alias != '\0') && g_utf8_validate(alias, -1, NULL))
- new_alias = purple_utf8_strip_unprintables(alias);
-
- if (!purple_strings_are_different(buddy->server_alias, new_alias)) {
- g_free(new_alias);
- return;
- }
-
- old_alias = buddy->server_alias;
-
- if ((new_alias != NULL) && (*new_alias != '\0'))
- buddy->server_alias = new_alias;
- else {
- buddy->server_alias = NULL;
- g_free(new_alias); /* could be "\0"; */
- }
-
- purple_blist_schedule_save();
-
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode *)buddy);
-
- conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, buddy->name,
- buddy->account);
- if (conv)
- purple_conversation_autoset_title(conv);
-
- purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
- buddy, old_alias);
- g_free(old_alias);
-}
-
-/*
- * TODO: If merging, prompt the user if they want to merge.
- */
-void purple_blist_rename_group(PurpleGroup *source, const char *name)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurpleGroup *dest;
- gchar *old_name;
- gchar *new_name;
- GList *moved_buddies = NULL;
- GSList *accts;
-
- g_return_if_fail(source != NULL);
- g_return_if_fail(name != NULL);
-
- new_name = purple_utf8_strip_unprintables(name);
-
- if (*new_name == '\0' || purple_strequal(new_name, source->name)) {
- g_free(new_name);
- return;
- }
-
- dest = purple_find_group(new_name);
- if (dest != NULL && purple_utf8_strcasecmp(source->name, dest->name) != 0) {
- /* We're merging two groups */
- PurpleBlistNode *prev, *child, *next;
-
- prev = purple_blist_get_last_child((PurpleBlistNode*)dest);
- child = ((PurpleBlistNode*)source)->child;
-
- /*
- * TODO: This seems like a dumb way to do this... why not just
- * append all children from the old group to the end of the new
- * one? PRPLs might be expecting to receive an add_buddy() for
- * each moved buddy...
- */
- while (child)
- {
- next = child->next;
- if (PURPLE_BLIST_NODE_IS_CONTACT(child)) {
- PurpleBlistNode *bnode;
- purple_blist_add_contact((PurpleContact *)child, dest, prev);
- for (bnode = child->child; bnode != NULL; bnode = bnode->next) {
- purple_blist_add_buddy((PurpleBuddy *)bnode, (PurpleContact *)child,
- NULL, bnode->prev);
- moved_buddies = g_list_append(moved_buddies, bnode);
- }
- prev = child;
- } else if (PURPLE_BLIST_NODE_IS_CHAT(child)) {
- purple_blist_add_chat((PurpleChat *)child, dest, prev);
- prev = child;
- } else {
- purple_debug(PURPLE_DEBUG_ERROR, "blist",
- "Unknown child type in group %s\n", source->name);
- }
- child = next;
- }
-
- /* Make a copy of the old group name and then delete the old group */
- old_name = g_strdup(source->name);
- purple_blist_remove_group(source);
- source = dest;
- g_free(new_name);
- } else {
- /* A simple rename */
- PurpleBlistNode *cnode, *bnode;
-
- /* Build a GList of all buddies in this group */
- for (cnode = ((PurpleBlistNode *)source)->child; cnode != NULL; cnode = cnode->next) {
- if (PURPLE_BLIST_NODE_IS_CONTACT(cnode))
- for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
- moved_buddies = g_list_append(moved_buddies, bnode);
- }
-
- old_name = source->name;
- source->name = new_name;
- }
-
- /* Save our changes */
- purple_blist_schedule_save();
-
- /* Update the UI */
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode*)source);
-
- /* Notify all PRPLs */
- /* TODO: Is this condition needed? Seems like it would always be TRUE */
- if(old_name && !purple_strequal(source->name, old_name)) {
- for (accts = purple_group_get_accounts(source); accts; accts = g_slist_remove(accts, accts->data)) {
- PurpleAccount *account = accts->data;
- PurpleConnection *gc = NULL;
- PurplePlugin *prpl = NULL;
- PurplePluginProtocolInfo *prpl_info = NULL;
- GList *l = NULL, *buddies = NULL;
-
- gc = purple_account_get_connection(account);
-
- if(gc)
- prpl = purple_connection_get_prpl(gc);
-
- if(gc && prpl)
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-
- if(!prpl_info)
- continue;
-
- for(l = moved_buddies; l; l = l->next) {
- PurpleBuddy *buddy = (PurpleBuddy *)l->data;
-
- if(buddy && buddy->account == account)
- buddies = g_list_append(buddies, (PurpleBlistNode *)buddy);
- }
-
- if(prpl_info->rename_group) {
- prpl_info->rename_group(gc, old_name, source, buddies);
- } else {
- GList *cur, *groups = NULL;
-
- /* Make a list of what the groups each buddy is in */
- for(cur = buddies; cur; cur = cur->next) {
- PurpleBlistNode *node = (PurpleBlistNode *)cur->data;
- groups = g_list_prepend(groups, node->parent->parent);
- }
-
- purple_account_remove_buddies(account, buddies, groups);
- g_list_free(groups);
- purple_account_add_buddies(account, buddies);
- }
-
- g_list_free(buddies);
- }
- }
- g_list_free(moved_buddies);
- g_free(old_name);
-}
-
-static void purple_blist_node_initialize_settings(PurpleBlistNode *node);
-
-PurpleChat *purple_chat_new(PurpleAccount *account, const char *alias, GHashTable *components)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurpleChat *chat;
-
- g_return_val_if_fail(account != NULL, FALSE);
- g_return_val_if_fail(components != NULL, FALSE);
-
- chat = g_new0(PurpleChat, 1);
- chat->account = account;
- if ((alias != NULL) && (*alias != '\0'))
- chat->alias = purple_utf8_strip_unprintables(alias);
- chat->components = components;
- purple_blist_node_initialize_settings((PurpleBlistNode *)chat);
- ((PurpleBlistNode *)chat)->type = PURPLE_BLIST_CHAT_NODE;
-
- if (ops != NULL && ops->new_node != NULL)
- ops->new_node((PurpleBlistNode *)chat);
-
- PURPLE_DBUS_REGISTER_POINTER(chat, PurpleChat);
- return chat;
-}
-
-void
-purple_chat_destroy(PurpleChat *chat)
-{
- g_hash_table_destroy(chat->components);
- g_hash_table_destroy(chat->node.settings);
- g_free(chat->alias);
- PURPLE_DBUS_UNREGISTER_POINTER(chat);
- g_free(chat);
-}
-
-PurpleBuddy *purple_buddy_new(PurpleAccount *account, const char *name, const char *alias)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurpleBuddy *buddy;
-
- g_return_val_if_fail(account != NULL, NULL);
- g_return_val_if_fail(name != NULL, NULL);
-
- buddy = g_new0(PurpleBuddy, 1);
- buddy->account = account;
- buddy->name = purple_utf8_strip_unprintables(name);
- buddy->alias = purple_utf8_strip_unprintables(alias);
- buddy->presence = purple_presence_new_for_buddy(buddy);
- ((PurpleBlistNode *)buddy)->type = PURPLE_BLIST_BUDDY_NODE;
-
- purple_presence_set_status_active(buddy->presence, "offline", TRUE);
-
- purple_blist_node_initialize_settings((PurpleBlistNode *)buddy);
-
- if (ops && ops->new_node)
- ops->new_node((PurpleBlistNode *)buddy);
-
- PURPLE_DBUS_REGISTER_POINTER(buddy, PurpleBuddy);
- return buddy;
-}
-
-void
-purple_buddy_destroy(PurpleBuddy *buddy)
-{
- PurplePlugin *prpl;
- PurplePluginProtocolInfo *prpl_info;
-
- /*
- * Tell the owner PRPL that we're about to free the buddy so it
- * can free proto_data
- */
- prpl = purple_find_prpl(purple_account_get_protocol_id(buddy->account));
- if (prpl) {
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
- if (prpl_info && prpl_info->buddy_free)
- prpl_info->buddy_free(buddy);
- }
-
- /* Delete the node */
- purple_buddy_icon_unref(buddy->icon);
- g_hash_table_destroy(buddy->node.settings);
- purple_presence_destroy(buddy->presence);
- g_free(buddy->name);
- g_free(buddy->alias);
- g_free(buddy->server_alias);
-
- PURPLE_DBUS_UNREGISTER_POINTER(buddy);
- g_free(buddy);
-
- /* FIXME: Once PurpleBuddy is a GObject, timeout callbacks can
- * g_object_ref() it when connecting the callback and
- * g_object_unref() it in the handler. That way, it won't
- * get freed while the timeout is pending and this line can
- * be removed. */
- while (g_source_remove_by_user_data((gpointer *)buddy));
-}
-
-void
-purple_buddy_set_icon(PurpleBuddy *buddy, PurpleBuddyIcon *icon)
-{
- g_return_if_fail(buddy != NULL);
-
- if (buddy->icon != icon)
- {
- purple_buddy_icon_unref(buddy->icon);
- buddy->icon = (icon != NULL ? purple_buddy_icon_ref(icon) : NULL);
- }
-
- purple_signal_emit(purple_blist_get_handle(), "buddy-icon-changed", buddy);
-
- purple_blist_update_node_icon((PurpleBlistNode*)buddy);
-}
-
-PurpleAccount *
-purple_buddy_get_account(const PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- return buddy->account;
-}
-
-const char *
-purple_buddy_get_name(const PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- return buddy->name;
-}
-
-PurpleBuddyIcon *
-purple_buddy_get_icon(const PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- return buddy->icon;
-}
-
-gpointer
-purple_buddy_get_protocol_data(const PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- return buddy->proto_data;
-}
-
-void
-purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data)
-{
- g_return_if_fail(buddy != NULL);
-
- buddy->proto_data = data;
-}
-
-
-void purple_blist_add_chat(PurpleChat *chat, PurpleGroup *group, PurpleBlistNode *node)
-{
- PurpleBlistNode *cnode = (PurpleBlistNode*)chat;
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
-
- g_return_if_fail(chat != NULL);
- g_return_if_fail(PURPLE_BLIST_NODE_IS_CHAT((PurpleBlistNode *)chat));
-
- if (node == NULL) {
- if (group == NULL)
- group = purple_group_new(_("Chats"));
-
- /* Add group to blist if isn't already on it. Fixes #2752. */
- if (!purple_find_group(group->name)) {
- purple_blist_add_group(group,
- purple_blist_get_last_sibling(purplebuddylist->root));
- }
- } else {
- group = (PurpleGroup*)node->parent;
- }
-
- /* if we're moving to overtop of ourselves, do nothing */
- if (cnode == node)
- return;
-
- if (cnode->parent) {
- /* This chat was already in the list and is
- * being moved.
- */
- ((PurpleGroup *)cnode->parent)->totalsize--;
- if (purple_account_is_connected(chat->account)) {
- ((PurpleGroup *)cnode->parent)->online--;
- ((PurpleGroup *)cnode->parent)->currentsize--;
- }
- if (cnode->next)
- cnode->next->prev = cnode->prev;
- if (cnode->prev)
- cnode->prev->next = cnode->next;
- if (cnode->parent->child == cnode)
- cnode->parent->child = cnode->next;
-
- if (ops && ops->remove)
- ops->remove(purplebuddylist, cnode);
- /* ops->remove() cleaned up the cnode's ui_data, so we need to
- * reinitialize it */
- if (ops && ops->new_node)
- ops->new_node(cnode);
-
- purple_blist_schedule_save();
- }
-
- if (node != NULL) {
- if (node->next)
- node->next->prev = cnode;
- cnode->next = node->next;
- cnode->prev = node;
- cnode->parent = node->parent;
- node->next = cnode;
- ((PurpleGroup *)node->parent)->totalsize++;
- if (purple_account_is_connected(chat->account)) {
- ((PurpleGroup *)node->parent)->online++;
- ((PurpleGroup *)node->parent)->currentsize++;
- }
- } else {
- if (((PurpleBlistNode *)group)->child)
- ((PurpleBlistNode *)group)->child->prev = cnode;
- cnode->next = ((PurpleBlistNode *)group)->child;
- cnode->prev = NULL;
- ((PurpleBlistNode *)group)->child = cnode;
- cnode->parent = (PurpleBlistNode *)group;
- group->totalsize++;
- if (purple_account_is_connected(chat->account)) {
- group->online++;
- group->currentsize++;
- }
- }
-
- purple_blist_schedule_save();
-
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode *)cnode);
-
- purple_signal_emit(purple_blist_get_handle(), "blist-node-added",
- cnode);
-}
-
-void purple_blist_add_buddy(PurpleBuddy *buddy, PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node)
-{
- PurpleBlistNode *cnode, *bnode;
- PurpleGroup *g;
- PurpleContact *c;
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- struct _purple_hbuddy *hb, *hb2;
- GHashTable *account_buddies;
-
- g_return_if_fail(buddy != NULL);
- g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY((PurpleBlistNode*)buddy));
-
- bnode = (PurpleBlistNode *)buddy;
-
- /* if we're moving to overtop of ourselves, do nothing */
- if (bnode == node || (!node && bnode->parent &&
- contact && bnode->parent == (PurpleBlistNode*)contact
- && bnode == bnode->parent->child))
- return;
-
- if (node && PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- c = (PurpleContact*)node->parent;
- g = (PurpleGroup*)node->parent->parent;
- } else if (contact) {
- c = contact;
- g = PURPLE_GROUP(PURPLE_BLIST_NODE(c)->parent);
- } else {
- g = group;
- if (g == NULL)
- g = purple_group_new(_("Buddies"));
- /* Add group to blist if isn't already on it. Fixes #2752. */
- if (!purple_find_group(g->name)) {
- purple_blist_add_group(g,
- purple_blist_get_last_sibling(purplebuddylist->root));
- }
- c = purple_contact_new();
- purple_blist_add_contact(c, g,
- purple_blist_get_last_child((PurpleBlistNode*)g));
- }
-
- cnode = (PurpleBlistNode *)c;
-
- if (bnode->parent) {
- if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
- ((PurpleContact*)bnode->parent)->online--;
- if (((PurpleContact*)bnode->parent)->online == 0)
- ((PurpleGroup*)bnode->parent->parent)->online--;
- }
- if (purple_account_is_connected(buddy->account)) {
- ((PurpleContact*)bnode->parent)->currentsize--;
- if (((PurpleContact*)bnode->parent)->currentsize == 0)
- ((PurpleGroup*)bnode->parent->parent)->currentsize--;
- }
- ((PurpleContact*)bnode->parent)->totalsize--;
- /* the group totalsize will be taken care of by remove_contact below */
-
- if (bnode->parent->parent != (PurpleBlistNode*)g)
- serv_move_buddy(buddy, (PurpleGroup *)bnode->parent->parent, g);
-
- if (bnode->next)
- bnode->next->prev = bnode->prev;
- if (bnode->prev)
- bnode->prev->next = bnode->next;
- if (bnode->parent->child == bnode)
- bnode->parent->child = bnode->next;
-
- if (ops && ops->remove)
- ops->remove(purplebuddylist, bnode);
-
- purple_blist_schedule_save();
-
- if (bnode->parent->parent != (PurpleBlistNode*)g) {
- hb = g_new(struct _purple_hbuddy, 1);
- hb->name = g_strdup(purple_normalize(buddy->account, buddy->name));
- hb->account = buddy->account;
- hb->group = bnode->parent->parent;
- g_hash_table_remove(purplebuddylist->buddies, hb);
-
- account_buddies = g_hash_table_lookup(buddies_cache, buddy->account);
- g_hash_table_remove(account_buddies, hb);
-
- g_free(hb->name);
- g_free(hb);
- }
-
- if (!bnode->parent->child) {
- purple_blist_remove_contact((PurpleContact*)bnode->parent);
- } else {
- purple_contact_invalidate_priority_buddy((PurpleContact*)bnode->parent);
- if (ops && ops->update)
- ops->update(purplebuddylist, bnode->parent);
- }
- }
-
- if (node && PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- if (node->next)
- node->next->prev = bnode;
- bnode->next = node->next;
- bnode->prev = node;
- bnode->parent = node->parent;
- node->next = bnode;
- } else {
- if (cnode->child)
- cnode->child->prev = bnode;
- bnode->prev = NULL;
- bnode->next = cnode->child;
- cnode->child = bnode;
- bnode->parent = cnode;
- }
-
- if (PURPLE_BUDDY_IS_ONLINE(buddy)) {
- if (++(PURPLE_CONTACT(bnode->parent)->online) == 1)
- PURPLE_GROUP(bnode->parent->parent)->online++;
- }
- if (purple_account_is_connected(buddy->account)) {
- if (++(PURPLE_CONTACT(bnode->parent)->currentsize) == 1)
- PURPLE_GROUP(bnode->parent->parent)->currentsize++;
- }
- PURPLE_CONTACT(bnode->parent)->totalsize++;
-
- hb = g_new(struct _purple_hbuddy, 1);
- hb->name = g_strdup(purple_normalize(buddy->account, buddy->name));
- hb->account = buddy->account;
- hb->group = ((PurpleBlistNode*)buddy)->parent->parent;
-
- g_hash_table_replace(purplebuddylist->buddies, hb, buddy);
-
- account_buddies = g_hash_table_lookup(buddies_cache, buddy->account);
-
- hb2 = g_new(struct _purple_hbuddy, 1);
- hb2->name = g_strdup(hb->name);
- hb2->account = buddy->account;
- hb2->group = ((PurpleBlistNode*)buddy)->parent->parent;
-
- g_hash_table_replace(account_buddies, hb2, buddy);
-
- purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
-
- purple_blist_schedule_save();
-
- if (ops && ops->update)
- ops->update(purplebuddylist, (PurpleBlistNode*)buddy);
-
- /* Signal that the buddy has been added */
- purple_signal_emit(purple_blist_get_handle(), "buddy-added", buddy);
-
- purple_signal_emit(purple_blist_get_handle(), "blist-node-added",
- PURPLE_BLIST_NODE(buddy));
-}
-
-PurpleContact *purple_contact_new()
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
-
- PurpleContact *contact = g_new0(PurpleContact, 1);
- contact->totalsize = 0;
- contact->currentsize = 0;
- contact->online = 0;
- purple_blist_node_initialize_settings((PurpleBlistNode *)contact);
- ((PurpleBlistNode *)contact)->type = PURPLE_BLIST_CONTACT_NODE;
-
- if (ops && ops->new_node)
- ops->new_node((PurpleBlistNode *)contact);
-
- PURPLE_DBUS_REGISTER_POINTER(contact, PurpleContact);
- return contact;
-}
-
-void
-purple_contact_destroy(PurpleContact *contact)
-{
- g_hash_table_destroy(contact->node.settings);
- g_free(contact->alias);
- PURPLE_DBUS_UNREGISTER_POINTER(contact);
- g_free(contact);
-}
-
-void purple_contact_set_alias(PurpleContact *contact, const char *alias)
-{
- purple_blist_alias_contact(contact,alias);
-}
-
-const char *purple_contact_get_alias(PurpleContact* contact)
-{
- g_return_val_if_fail(contact != NULL, NULL);
-
- if (contact->alias)
- return contact->alias;
-
- return purple_buddy_get_alias(purple_contact_get_priority_buddy(contact));
-}
-
-gboolean purple_contact_on_account(PurpleContact *c, PurpleAccount *account)
-{
- PurpleBlistNode *bnode, *cnode = (PurpleBlistNode *) c;
-
- g_return_val_if_fail(c != NULL, FALSE);
- g_return_val_if_fail(account != NULL, FALSE);
-
- for (bnode = cnode->child; bnode; bnode = bnode->next) {
- PurpleBuddy *buddy;
-
- if (! PURPLE_BLIST_NODE_IS_BUDDY(bnode))
- continue;
-
- buddy = (PurpleBuddy *)bnode;
- if (buddy->account == account)
- return TRUE;
- }
- return FALSE;
-}
-
-void purple_contact_invalidate_priority_buddy(PurpleContact *contact)
-{
- g_return_if_fail(contact != NULL);
-
- contact->priority_valid = FALSE;
-}
-
-PurpleGroup *purple_group_new(const char *name)
-{
- PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
- PurpleGroup *group;
-
- g_return_val_if_fail(name != NULL, NULL);
- g_return_val_if_fail(*name != '\0', NULL);
-
- group = purple_find_group(name);
- if (group != NULL)
- return group;
-
- group = g_new0(PurpleGroup, 1);
- group->name = purple_utf8_strip_unprintables(name);
- group->totalsize = 0;
- group->currentsize = 0;
- group->online = 0;
- purple_blist_node_initialize_settings((PurpleBlistNode *)group);
- ((PurpleBlistNode *)group)->type = PURPLE_BLIST_GROUP_NODE;
-
- if (ops && ops->new_node)
- ops->new_node((PurpleBlistNode *)group);
-
- PURPLE_DBUS_REGISTER_POINTER(group, PurpleGroup);
- return group;
-}
-
-void
-purple_group_destroy(PurpleGroup *group)
-{
- g_hash_table_destroy(group->node.settings);
- g_free(group->name);
- PURPLE_DBUS_UNREGISTER_POINTER(group);
- g_free(group);
-}
-
void purple_blist_add_contact(PurpleContact *contact, PurpleGroup *group, PurpleBlistNode *node)
{
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
@@ -1916,42 +573,6 @@ void purple_blist_add_contact(PurpleCont
}
}
-void purple_blist_merge_contact(PurpleContact *source, PurpleBlistNode *node)
-{
- PurpleBlistNode *sourcenode = (PurpleBlistNode*)source;
- PurpleBlistNode *targetnode;
- PurpleBlistNode *prev, *cur, *next;
- PurpleContact *target;
-
- g_return_if_fail(source != NULL);
- g_return_if_fail(node != NULL);
-
- if (PURPLE_BLIST_NODE_IS_CONTACT(node)) {
- target = (PurpleContact *)node;
- prev = purple_blist_get_last_child(node);
- } else if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
- target = (PurpleContact *)node->parent;
- prev = node;
- } else {
- return;
- }
-
- if (source == target || !target)
- return;
-
- targetnode = (PurpleBlistNode *)target;
- next = sourcenode->child;
-
- while (next) {
- cur = next;
- next = cur->next;
- if (PURPLE_BLIST_NODE_IS_BUDDY(cur)) {
- purple_blist_add_buddy((PurpleBuddy *)cur, target, NULL, prev);
- prev = cur;
- }
- }
-}
-
void purple_blist_add_group(PurpleGroup *group, PurpleBlistNode *node)
{
PurpleBlistUiOps *ops;
@@ -2223,136 +844,7 @@ void purple_blist_remove_group(PurpleGro
purple_group_destroy(group);
}
-PurpleBuddy *purple_contact_get_priority_buddy(PurpleContact *contact)
-{
- g_return_val_if_fail(contact != NULL, NULL);
- if (!contact->priority_valid)
- purple_contact_compute_priority_buddy(contact);
-
- return contact->priority;
-}
-
-const char *purple_buddy_get_alias_only(PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- if ((buddy->alias != NULL) && (*buddy->alias != '\0')) {
- return buddy->alias;
- } else if ((purple_buddy_get_server_alias(buddy) != NULL) &&
- (*purple_buddy_get_server_alias(buddy) != '\0')) {
-
- return purple_buddy_get_server_alias(buddy);
- }
-
- return NULL;
-}
-
-
-const char *purple_buddy_get_contact_alias(PurpleBuddy *buddy)
-{
- PurpleContact *c;
-
- g_return_val_if_fail(buddy != NULL, NULL);
-
- /* Search for an alias for the buddy. In order of precedence: */
- /* The buddy alias */
- if (buddy->alias != NULL)
- return buddy->alias;
-
- /* The contact alias */
- c = purple_buddy_get_contact(buddy);
- if ((c != NULL) && (c->alias != NULL))
- return c->alias;
-
- /* The server alias */
- if ((purple_buddy_get_server_alias(buddy)) && (*purple_buddy_get_server_alias(buddy)))
- return purple_buddy_get_server_alias(buddy);
-
- /* The buddy's user name (i.e. no alias) */
- return buddy->name;
-}
-
-
-const char *purple_buddy_get_alias(PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- /* Search for an alias for the buddy. In order of precedence: */
- /* The buddy alias */
- if (buddy->alias != NULL)
- return buddy->alias;
-
- /* The server alias */
- if ((purple_buddy_get_server_alias(buddy)) && (*purple_buddy_get_server_alias(buddy)))
- return purple_buddy_get_server_alias(buddy);
-
- /* The buddy's user name (i.e. no alias) */
- return buddy->name;
-}
-
-const char *purple_buddy_get_local_buddy_alias(PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy, NULL);
- return buddy->alias;
-}
-
-const char *purple_buddy_get_server_alias(PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- if ((buddy->server_alias) && (*buddy->server_alias))
- return buddy->server_alias;
-
- return NULL;
-}
-
-const char *purple_buddy_get_local_alias(PurpleBuddy *buddy)
-{
- PurpleContact *c;
-
- g_return_val_if_fail(buddy != NULL, NULL);
-
- /* Search for an alias for the buddy. In order of precedence: */
- /* The buddy alias */
- if (buddy->alias != NULL)
- return buddy->alias;
-
- /* The contact alias */
- c = purple_buddy_get_contact(buddy);
- if ((c != NULL) && (c->alias != NULL))
- return c->alias;
-
- /* The buddy's user name (i.e. no alias) */
- return buddy->name;
-}
-
-const char *purple_chat_get_name(PurpleChat *chat)
-{
- char *ret = NULL;
- PurplePlugin *prpl;
- PurplePluginProtocolInfo *prpl_info = NULL;
-
- g_return_val_if_fail(chat != NULL, NULL);
-
- if ((chat->alias != NULL) && (*chat->alias != '\0'))
- return chat->alias;
-
- prpl = purple_find_prpl(purple_account_get_protocol_id(chat->account));
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-
- if (prpl_info->chat_info) {
- struct proto_chat_entry *pce;
- GList *parts = prpl_info->chat_info(purple_account_get_connection(chat->account));
- pce = parts->data;
- ret = g_hash_table_lookup(chat->components, pce->identifier);
- g_list_foreach(parts, (GFunc)g_free, NULL);
- g_list_free(parts);
- }
-
- return ret;
-}
-
PurpleBuddy *purple_find_buddy(PurpleAccount *account, const char *name)
{
PurpleBuddy *buddy;
@@ -2378,26 +870,6 @@ PurpleBuddy *purple_find_buddy(PurpleAcc
return NULL;
}
-PurpleBuddy *purple_find_buddy_in_group(PurpleAccount *account, const char *name,
- PurpleGroup *group)
-{
- struct _purple_hbuddy hb;
- PurpleBuddy *ret;
-
- g_return_val_if_fail(purplebuddylist != NULL, NULL);
- g_return_val_if_fail(account != NULL, NULL);
- g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
-
- hb.name = g_strdup(purple_normalize(account, name));
- hb.account = account;
- hb.group = (PurpleBlistNode*)group;
-
- ret = g_hash_table_lookup(purplebuddylist->buddies, &hb);
- g_free(hb.name);
-
- return ret;
-}
-
static void find_acct_buddies(gpointer key, gpointer value, gpointer data)
{
PurpleBuddy *buddy = value;
@@ -2437,124 +909,6 @@ GSList *purple_find_buddies(PurpleAccoun
return ret;
}
-PurpleGroup *purple_find_group(const char *name)
-{
- PurpleBlistNode *node;
-
- g_return_val_if_fail(purplebuddylist != NULL, NULL);
- g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
-
- for (node = purplebuddylist->root; node != NULL; node = node->next) {
- if (!purple_utf8_strcasecmp(((PurpleGroup *)node)->name, name))
- return (PurpleGroup *)node;
- }
-
- return NULL;
-}
-
-PurpleChat *
-purple_blist_find_chat(PurpleAccount *account, const char *name)
-{
- char *chat_name;
- PurpleChat *chat;
- PurplePlugin *prpl;
- PurplePluginProtocolInfo *prpl_info = NULL;
- struct proto_chat_entry *pce;
- PurpleBlistNode *node, *group;
- GList *parts;
- char *normname;
-
- g_return_val_if_fail(purplebuddylist != NULL, NULL);
- g_return_val_if_fail((name != NULL) && (*name != '\0'), NULL);
-
- if (!purple_account_is_connected(account))
- return NULL;
-
- prpl = purple_find_prpl(purple_account_get_protocol_id(account));
- prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
-
- if (prpl_info->find_blist_chat != NULL)
- return prpl_info->find_blist_chat(account, name);
-
- normname = g_strdup(purple_normalize(account, name));
- for (group = purplebuddylist->root; group != NULL; group = group->next) {
- for (node = group->child; node != NULL; node = node->next) {
- if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
-
- chat = (PurpleChat*)node;
-
- if (account != chat->account)
- continue;
-
- parts = prpl_info->chat_info(
- purple_account_get_connection(chat->account));
-
- pce = parts->data;
- chat_name = g_hash_table_lookup(chat->components,
- pce->identifier);
- g_list_foreach(parts, (GFunc)g_free, NULL);
- g_list_free(parts);
-
- if (chat->account == account && chat_name != NULL &&
- normname != NULL && !strcmp(purple_normalize(account, chat_name), normname)) {
- g_free(normname);
- return chat;
- }
- }
- }
- }
-
- g_free(normname);
- return NULL;
-}
-
-PurpleGroup *
-purple_chat_get_group(PurpleChat *chat)
-{
- g_return_val_if_fail(chat != NULL, NULL);
-
- return (PurpleGroup *)(((PurpleBlistNode *)chat)->parent);
-}
-
-PurpleAccount *
-purple_chat_get_account(PurpleChat *chat)
-{
- g_return_val_if_fail(chat != NULL, NULL);
-
- return chat->account;
-}
-
-GHashTable *
-purple_chat_get_components(PurpleChat *chat)
-{
- g_return_val_if_fail(chat != NULL, NULL);
-
- return chat->components;
-}
-
-PurpleContact *purple_buddy_get_contact(PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- return PURPLE_CONTACT(PURPLE_BLIST_NODE(buddy)->parent);
-}
-
-PurplePresence *purple_buddy_get_presence(const PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
- return buddy->presence;
-}
-
-PurpleGroup *purple_buddy_get_group(PurpleBuddy *buddy)
-{
- g_return_val_if_fail(buddy != NULL, NULL);
-
- if (((PurpleBlistNode *)buddy)->parent == NULL)
- return NULL;
-
- return (PurpleGroup *)(((PurpleBlistNode*)buddy)->parent->parent);
-}
-
GSList *purple_group_get_accounts(PurpleGroup *group)
{
GSList *l = NULL;
@@ -2723,13 +1077,6 @@ gboolean purple_group_on_account(PurpleG
return FALSE;
}
-const char *purple_group_get_name(PurpleGroup *group)
-{
- g_return_val_if_fail(group != NULL, NULL);
-
- return group->name;
-}
-
void
purple_blist_request_add_buddy(PurpleAccount *account, const char *username,
const char *group, const char *alias)
@@ -2765,231 +1112,7 @@ purple_blist_request_add_group(void)
ui_ops->request_add_group();
}
-static void
-purple_blist_node_destroy(PurpleBlistNode *node)
-{
- PurpleBlistUiOps *ui_ops;
- PurpleBlistNode *child, *next_child;
-
- ui_ops = purple_blist_get_ui_ops();
- child = node->child;
- while (child) {
- next_child = child->next;
- purple_blist_node_destroy(child);
- child = next_child;
- }
-
- /* Allow the UI to free data */
- node->parent = NULL;
- node->child = NULL;
- node->next = NULL;
- node->prev = NULL;
- if (ui_ops && ui_ops->remove)
- ui_ops->remove(purplebuddylist, node);
-
- if (PURPLE_BLIST_NODE_IS_BUDDY(node))
- purple_buddy_destroy((PurpleBuddy*)node);
- else if (PURPLE_BLIST_NODE_IS_CHAT(node))
- purple_chat_destroy((PurpleChat*)node);
- else if (PURPLE_BLIST_NODE_IS_CONTACT(node))
- purple_contact_destroy((PurpleContact*)node);
- else if (PURPLE_BLIST_NODE_IS_GROUP(node))
- purple_group_destroy((PurpleGroup*)node);
-}
-
-static void purple_blist_node_initialize_settings(PurpleBlistNode *node)
-{
- if (node->settings)
- return;
-
- node->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
- (GDestroyNotify)purple_g_value_slice_free);
-}
-
-void purple_blist_node_remove_setting(PurpleBlistNode *node, const char *key)
-{
- g_return_if_fail(node != NULL);
- g_return_if_fail(node->settings != NULL);
- g_return_if_fail(key != NULL);
-
- g_hash_table_remove(node->settings, key);
-
- purple_blist_schedule_save();
-}
-
void
-purple_blist_node_set_flags(PurpleBlistNode *node, PurpleBlistNodeFlags flags)
-{
- g_return_if_fail(node != NULL);
-
- node->flags = flags;
-}
-
-PurpleBlistNodeFlags
-purple_blist_node_get_flags(PurpleBlistNode *node)
-{
- g_return_val_if_fail(node != NULL, 0);
-
- return node->flags;
-}
-
-PurpleBlistNodeType
-purple_blist_node_get_type(PurpleBlistNode *node)
-{
- g_return_val_if_fail(node != NULL, PURPLE_BLIST_OTHER_NODE);
- return node->type;
-}
-
-
-gboolean
-purple_blist_node_has_setting(PurpleBlistNode *node,
- const char *key)
-{
- g_return_val_if_fail(node != NULL, FALSE);
- g_return_val_if_fail(node->settings != NULL, FALSE);
- g_return_val_if_fail(key != NULL, FALSE);
-
- return (g_hash_table_lookup(node->settings, key) != NULL);
-}
-
-void
-purple_blist_node_set_bool(PurpleBlistNode* node, const char *key, gboolean data)
-{
- GValue *value;
-
- g_return_if_fail(node != NULL);
- g_return_if_fail(node->settings != NULL);
- g_return_if_fail(key != NULL);
-
- value = purple_g_value_slice_new(G_TYPE_BOOLEAN);
- g_value_set_boolean(value, data);
-
- g_hash_table_replace(node->settings, g_strdup(key), value);
-
- purple_blist_schedule_save();
-}
-
-gboolean
-purple_blist_node_get_bool(PurpleBlistNode* node, const char *key)
-{
- GValue *value;
-
- g_return_val_if_fail(node != NULL, FALSE);
- g_return_val_if_fail(node->settings != NULL, FALSE);
- g_return_val_if_fail(key != NULL, FALSE);
-
- value = g_hash_table_lookup(node->settings, key);
-
- if (value == NULL)
- return FALSE;
-
- g_return_val_if_fail(G_VALUE_HOLDS_BOOLEAN(value), FALSE);
-
- return g_value_get_boolean(value);
-}
-
-void
-purple_blist_node_set_int(PurpleBlistNode* node, const char *key, int data)
-{
- GValue *value;
-
- g_return_if_fail(node != NULL);
- g_return_if_fail(node->settings != NULL);
- g_return_if_fail(key != NULL);
-
- value = purple_g_value_slice_new(G_TYPE_INT);
- g_value_set_int(value, data);
-
- g_hash_table_replace(node->settings, g_strdup(key), value);
-
- purple_blist_schedule_save();
-}
-
-int
-purple_blist_node_get_int(PurpleBlistNode* node, const char *key)
-{
- GValue *value;
-
- g_return_val_if_fail(node != NULL, 0);
- g_return_val_if_fail(node->settings != NULL, 0);
- g_return_val_if_fail(key != NULL, 0);
-
- value = g_hash_table_lookup(node->settings, key);
-
- if (value == NULL)
- return 0;
-
- g_return_val_if_fail(G_VALUE_HOLDS_INT(value), 0);
-
- return g_value_get_int(value);
-}
-
-void
-purple_blist_node_set_string(PurpleBlistNode* node, const char *key, const char *data)
-{
- GValue *value;
-
- g_return_if_fail(node != NULL);
- g_return_if_fail(node->settings != NULL);
- g_return_if_fail(key != NULL);
-
- value = purple_g_value_slice_new(G_TYPE_STRING);
- g_value_set_string(value, data);
-
- g_hash_table_replace(node->settings, g_strdup(key), value);
-
- purple_blist_schedule_save();
-}
-
-const char *
-purple_blist_node_get_string(PurpleBlistNode* node, const char *key)
-{
- GValue *value;
-
- g_return_val_if_fail(node != NULL, NULL);
- g_return_val_if_fail(node->settings != NULL, NULL);
- g_return_val_if_fail(key != NULL, NULL);
-
- value = g_hash_table_lookup(node->settings, key);
-
- if (value == NULL)
- return NULL;
-
- g_return_val_if_fail(G_VALUE_HOLDS_STRING(value), NULL);
-
- return g_value_get_string(value);
-}
-
-GList *
-purple_blist_node_get_extended_menu(PurpleBlistNode *n)
-{
- GList *menu = NULL;
-
- g_return_val_if_fail(n != NULL, NULL);
-
- purple_signal_emit(purple_blist_get_handle(),
- "blist-node-extended-menu",
- n, &menu);
- return menu;
-}
-
-int purple_blist_get_group_size(PurpleGroup *group, gboolean offline)
-{
- if (!group)
- return 0;
-
- return offline ? group->totalsize : group->currentsize;
-}
-
-int purple_blist_get_group_online_count(PurpleGroup *group)
-{
- if (!group)
- return 0;
-
- return group->online;
-}
-
-void
purple_blist_set_ui_ops(PurpleBlistUiOps *ops)
{
blist_ui_ops = ops;
@@ -3132,4 +1255,4 @@ purple_blist_uninit(void)
purple_signals_disconnect_by_handle(purple_blist_get_handle());
purple_signals_unregister_by_instance(purple_blist_get_handle());
-}
+};
============================================================
--- libpurple/blist.h 5d2b355c508232845cfbdc865e46aeb57260d849
+++ libpurple/blist.h 1e32736797585033d30e01130064724e5e965955
@@ -228,6 +228,44 @@ struct _PurpleBlistUiOps
void (*_purple_reserved4)(void);
};
+#ifdef _BLIST_HELPERS_
+
+void value_to_xmlnode(gpointer key, gpointer hvalue, gpointer user_data);
+xmlnode *contact_to_xmlnode(PurpleBlistNode *cnode);
+xmlnode *chat_to_xmlnode(PurpleBlistNode *cnode);
+xmlnode *buddy_to_xmlnode(PurpleBlistNode *bnode);
+xmlnode *group_to_xmlnode(PurpleBlistNode *bnode);
+PurpleBlistNode *purple_blist_get_last_sibling(PurpleBlistNode *node);
+PurpleBlistNode *purple_blist_get_last_child(PurpleBlistNode *node);
+void parse_setting(PurpleBlistNode *node, xmlnode *setting);
+void parse_contact(PurpleGroup *group, xmlnode *cnode);
+void parse_chat(PurpleGroup *group, xmlnode *cnode);
+void parse_buddy(PurpleGroup *group, PurpleContact *contact, xmlnode *bnode);
+void parse_group(xmlnode *groupnode);
+void purple_contact_compute_priority_buddy(PurpleContact *contact);
+gboolean purple_strings_are_different(const char *one, const char *two);
+
+/* The global static members */
+struct _list_account_buddies {
+ GSList *list;
+ PurpleAccount *account;
+};
+
+struct _purple_hbuddy {
+ char *name;
+ PurpleAccount *account;
+ PurpleBlistNode *group;
+};
+
+PurpleBuddyList* purple_blist_get_list(void);
+GHashTable* purple_blist_get_buddies_cache(void);
+guint purple_blist_get_save_timer(void);
+gboolean purple_blist_get_blist_loaded(void);
+void purple_blist_node_initialize_settings(PurpleBlistNode *node);
+void purple_blist_node_destroy(PurpleBlistNode* node);
+
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -418,7 +456,7 @@ void purple_blist_update_node_icon(Purpl
*/
void purple_blist_update_node_icon(PurpleBlistNode *node);
-#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_BLIST_C_)
+#if !(defined PURPLE_DISABLE_DEPRECATED) || (defined _PURPLE_BUDDY_C_)
/**
* Updates a buddy's icon.
*
More information about the Commits
mailing list