pidgin/pidgin

Remove GtkImHtml dependency from buddy list

2014-01-31, Tomasz Wasilczyk
134f3e8c5c6c
Remove GtkImHtml dependency from buddy list
/*
* 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
*
*/
#include "internal.h"
#include "glibcompat.h"
#include "dbus-maybe.h"
#include "debug.h"
#define PURPLE_BUDDY_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_BUDDY, PurpleBuddyPrivate))
/** @copydoc _PurpleBuddyPrivate */
typedef struct _PurpleBuddyPrivate PurpleBuddyPrivate;
#define PURPLE_CONTACT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_CONTACT, PurpleContactPrivate))
/** @copydoc _PurpleContactPrivate */
typedef struct _PurpleContactPrivate PurpleContactPrivate;
#define PURPLE_GROUP_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_GROUP, PurpleGroupPrivate))
/** @copydoc _PurpleGroupPrivate */
typedef struct _PurpleGroupPrivate PurpleGroupPrivate;
#define PURPLE_CHAT_GET_PRIVATE(obj) \
(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_CHAT, PurpleChatPrivate))
/** @copydoc _PurpleChatPrivate */
typedef struct _PurpleChatPrivate PurpleChatPrivate;
/**************************************************************************/
/* Private data */
/**************************************************************************/
/** Private data for a buddy. */
struct _PurpleBuddyPrivate {
char *name; /**< The name of the buddy. */
char *local_alias; /**< The user-set alias of the buddy */
char *server_alias; /**< The server-specified alias of the buddy.
(i.e. MSN "Friendly Names") */
void *proto_data; /**< This allows the prpl to associate
whatever data it wants with a buddy. */
PurpleBuddyIcon *icon; /**< The buddy icon. */
PurpleAccount *account; /**< the account this buddy belongs to */
PurplePresence *presence; /**< Presense information of the buddy */
PurpleMediaCaps media_caps; /**< The media capabilities of the buddy. */
gboolean is_constructed; /**< Indicates if the buddy has finished
being constructed. */
};
/* Buddy property enums */
enum
{
BUDDY_PROP_0,
BUDDY_PROP_NAME,
BUDDY_PROP_LOCAL_ALIAS,
BUDDY_PROP_SERVER_ALIAS,
BUDDY_PROP_ICON,
BUDDY_PROP_ACCOUNT,
BUDDY_PROP_PRESENCE,
BUDDY_PROP_MEDIA_CAPS,
BUDDY_PROP_LAST
};
/** Private data for a contact */
struct _PurpleContactPrivate {
char *alias; /**< The user-set alias of the contact */
PurpleBuddy *priority_buddy; /**< The "top" buddy for this contact */
gboolean priority_valid; /**< Is priority valid? */
};
/* Contact property enums */
enum
{
CONTACT_PROP_0,
CONTACT_PROP_ALIAS,
CONTACT_PROP_PRIORITY_BUDDY,
CONTACT_PROP_LAST
};
/** Private data for a group */
struct _PurpleGroupPrivate {
char *name; /**< The name of this group. */
gboolean is_constructed; /**< Indicates if the group has finished being
constructed. */
};
/* Group property enums */
enum
{
GROUP_PROP_0,
GROUP_PROP_NAME,
GROUP_PROP_LAST
};
/** Private data for a chat node */
struct _PurpleChatPrivate {
char *alias; /**< The display name of this chat. */
PurpleAccount *account; /**< The account this chat is attached to */
GHashTable *components; /**< the stuff the protocol needs to know to
join the chat */
gboolean is_constructed; /**< Indicates if the chat has finished being
constructed. */
};
/* Chat property enums */
enum
{
CHAT_PROP_0,
CHAT_PROP_ALIAS,
CHAT_PROP_ACCOUNT,
CHAT_PROP_COMPONENTS,
CHAT_PROP_LAST
};
static PurpleBlistNode *blistnode_parent_class;
static PurpleCountingNode *counting_parent_class;
static GParamSpec *bd_properties[BUDDY_PROP_LAST];
static GParamSpec *co_properties[CONTACT_PROP_LAST];
static GParamSpec *gr_properties[GROUP_PROP_LAST];
static GParamSpec *ch_properties[CHAT_PROP_LAST];
static 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')));
}
/**************************************************************************/
/* Buddy API */
/**************************************************************************/
void
purple_buddy_set_icon(PurpleBuddy *buddy, PurpleBuddyIcon *icon)
{
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_if_fail(priv != NULL);
if (priv->icon != icon)
{
purple_buddy_icon_unref(priv->icon);
priv->icon = (icon != NULL ? purple_buddy_icon_ref(icon) : NULL);
g_object_notify_by_pspec(G_OBJECT(buddy),
bd_properties[BUDDY_PROP_ICON]);
}
purple_signal_emit(purple_blist_get_handle(), "buddy-icon-changed", buddy);
if (ops && ops->update)
ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(buddy));
}
PurpleBuddyIcon *
purple_buddy_get_icon(const PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
return priv->icon;
}
PurpleAccount *
purple_buddy_get_account(const PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
return priv->account;
}
void
purple_buddy_set_name(PurpleBuddy *buddy, const char *name)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
g_return_if_fail(priv != NULL);
purple_blist_update_buddies_cache(buddy, name);
g_free(priv->name);
priv->name = purple_utf8_strip_unprintables(name);
g_object_notify_by_pspec(G_OBJECT(buddy), bd_properties[BUDDY_PROP_NAME]);
if (ops) {
if (ops->save_node)
ops->save_node(PURPLE_BLIST_NODE(buddy));
if (ops->update)
ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(buddy));
}
}
const char *
purple_buddy_get_name(const PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
return priv->name;
}
gpointer
purple_buddy_get_protocol_data(const PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
return priv->proto_data;
}
void
purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_if_fail(priv != NULL);
priv->proto_data = data;
}
const char *purple_buddy_get_alias_only(PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
if ((priv->local_alias != NULL) && (*priv->local_alias != '\0')) {
return priv->local_alias;
} else if ((priv->server_alias != NULL) &&
(*priv->server_alias != '\0')) {
return priv->server_alias;
}
return NULL;
}
const char *purple_buddy_get_contact_alias(PurpleBuddy *buddy)
{
PurpleContact *c;
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
/* Search for an alias for the buddy. In order of precedence: */
/* The local buddy alias */
if (priv->local_alias != NULL)
return priv->local_alias;
/* The contact alias */
c = purple_buddy_get_contact(buddy);
if ((c != NULL) && (purple_contact_get_alias(c) != NULL))
return purple_contact_get_alias(c);
/* The server alias */
if ((priv->server_alias) && (*priv->server_alias))
return priv->server_alias;
/* The buddy's user name (i.e. no alias) */
return priv->name;
}
const char *purple_buddy_get_alias(PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
/* Search for an alias for the buddy. In order of precedence: */
/* The buddy alias */
if (priv->local_alias != NULL)
return priv->local_alias;
/* The server alias */
if ((priv->server_alias) && (*priv->server_alias))
return priv->server_alias;
/* The buddy's user name (i.e. no alias) */
return priv->name;
}
void
purple_buddy_set_local_alias(PurpleBuddy *buddy, const char *alias)
{
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
PurpleIMConversation *im;
char *old_alias;
char *new_alias = NULL;
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_if_fail(priv != NULL);
if ((alias != NULL) && (*alias != '\0'))
new_alias = purple_utf8_strip_unprintables(alias);
if (!purple_strings_are_different(priv->local_alias, new_alias)) {
g_free(new_alias);
return;
}
old_alias = priv->local_alias;
if ((new_alias != NULL) && (*new_alias != '\0'))
priv->local_alias = new_alias;
else {
priv->local_alias = NULL;
g_free(new_alias); /* could be "\0" */
}
g_object_notify_by_pspec(G_OBJECT(buddy),
bd_properties[BUDDY_PROP_LOCAL_ALIAS]);
if (ops && ops->save_node)
ops->save_node(PURPLE_BLIST_NODE(buddy));
if (ops && ops->update)
ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(buddy));
im = purple_conversations_find_im_with_account(priv->name,
priv->account);
if (im)
purple_conversation_autoset_title(PURPLE_CONVERSATION(im));
purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
buddy, old_alias);
g_free(old_alias);
}
const char *purple_buddy_get_local_alias(PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
return priv->local_alias;
}
void
purple_buddy_set_server_alias(PurpleBuddy *buddy, const char *alias)
{
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
PurpleIMConversation *im;
char *old_alias;
char *new_alias = NULL;
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_if_fail(priv != NULL);
if ((alias != NULL) && (*alias != '\0') && g_utf8_validate(alias, -1, NULL))
new_alias = purple_utf8_strip_unprintables(alias);
if (!purple_strings_are_different(priv->server_alias, new_alias)) {
g_free(new_alias);
return;
}
old_alias = priv->server_alias;
if ((new_alias != NULL) && (*new_alias != '\0'))
priv->server_alias = new_alias;
else {
priv->server_alias = NULL;
g_free(new_alias); /* could be "\0"; */
}
g_object_notify_by_pspec(G_OBJECT(buddy),
bd_properties[BUDDY_PROP_SERVER_ALIAS]);
if (ops) {
if (ops->save_node)
ops->save_node(PURPLE_BLIST_NODE(buddy));
if (ops->update)
ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(buddy));
}
im = purple_conversations_find_im_with_account(priv->name,
priv->account);
if (im)
purple_conversation_autoset_title(PURPLE_CONVERSATION(im));
purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
buddy, old_alias);
g_free(old_alias);
}
const char *purple_buddy_get_server_alias(PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
if ((priv->server_alias) && (*priv->server_alias))
return priv->server_alias;
return NULL;
}
PurpleContact *purple_buddy_get_contact(PurpleBuddy *buddy)
{
g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
return PURPLE_CONTACT(PURPLE_BLIST_NODE(buddy)->parent);
}
PurplePresence *purple_buddy_get_presence(const PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, NULL);
return priv->presence;
}
void
purple_buddy_update_status(PurpleBuddy *buddy, PurpleStatus *old_status)
{
PurpleStatus *status;
PurpleBlistNode *cnode;
PurpleContact *contact;
PurpleCountingNode *contact_counter, *group_counter;
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_if_fail(priv != NULL);
status = purple_presence_get_active_status(priv->presence);
purple_debug_info("blistnodetypes", "Updating buddy status for %s (%s)\n",
priv->name, purple_account_get_protocol_name(priv->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 = PURPLE_BLIST_NODE(buddy)->parent;
contact = PURPLE_CONTACT(cnode);
contact_counter = PURPLE_COUNTING_NODE(contact);
group_counter = PURPLE_COUNTING_NODE(cnode->parent);
purple_counting_node_change_online_count(contact_counter, +1);
if (purple_counting_node_get_online_count(contact_counter) == 1)
purple_counting_node_change_online_count(group_counter, +1);
} else if (!purple_status_is_online(status) &&
purple_status_is_online(old_status)) {
purple_blist_node_set_int(PURPLE_BLIST_NODE(buddy), "last_seen", time(NULL));
purple_signal_emit(purple_blist_get_handle(), "buddy-signed-off", buddy);
cnode = PURPLE_BLIST_NODE(buddy)->parent;
contact = PURPLE_CONTACT(cnode);
contact_counter = PURPLE_COUNTING_NODE(contact);
group_counter = PURPLE_COUNTING_NODE(cnode->parent);
purple_counting_node_change_online_count(contact_counter, -1);
if (purple_counting_node_get_online_count(contact_counter) == 0)
purple_counting_node_change_online_count(group_counter, -1);
} 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_buddy_list(), PURPLE_BLIST_NODE(buddy));
}
PurpleMediaCaps purple_buddy_get_media_caps(const PurpleBuddy *buddy)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_val_if_fail(priv != NULL, 0);
return priv->media_caps;
}
void purple_buddy_set_media_caps(PurpleBuddy *buddy, PurpleMediaCaps media_caps)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
g_return_if_fail(priv != NULL);
priv->media_caps = media_caps;
g_object_notify_by_pspec(G_OBJECT(buddy),
bd_properties[BUDDY_PROP_MEDIA_CAPS]);
}
PurpleGroup *purple_buddy_get_group(PurpleBuddy *buddy)
{
g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
if (PURPLE_BLIST_NODE(buddy)->parent == NULL)
return NULL;
return PURPLE_GROUP(PURPLE_BLIST_NODE(buddy)->parent->parent);
}
/**************************************************************************
* GObject code for PurpleBuddy
**************************************************************************/
/* Set method for GObject properties */
static void
purple_buddy_set_property(GObject *obj, guint param_id, const GValue *value,
GParamSpec *pspec)
{
PurpleBuddy *buddy = PURPLE_BUDDY(obj);
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
switch (param_id) {
case BUDDY_PROP_NAME:
if (priv->is_constructed)
purple_buddy_set_name(buddy, g_value_get_string(value));
else
priv->name =
purple_utf8_strip_unprintables(g_value_get_string(value));
break;
case BUDDY_PROP_LOCAL_ALIAS:
if (priv->is_constructed)
purple_buddy_set_local_alias(buddy, g_value_get_string(value));
else
priv->local_alias =
purple_utf8_strip_unprintables(g_value_get_string(value));
break;
case BUDDY_PROP_SERVER_ALIAS:
purple_buddy_set_server_alias(buddy, g_value_get_string(value));
break;
case BUDDY_PROP_ICON:
purple_buddy_set_icon(buddy, g_value_get_pointer(value));
break;
case BUDDY_PROP_ACCOUNT:
priv->account = g_value_get_object(value);
break;
case BUDDY_PROP_MEDIA_CAPS:
purple_buddy_set_media_caps(buddy, g_value_get_enum(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* Get method for GObject properties */
static void
purple_buddy_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *pspec)
{
PurpleBuddy *buddy = PURPLE_BUDDY(obj);
switch (param_id) {
case BUDDY_PROP_NAME:
g_value_set_string(value, purple_buddy_get_name(buddy));
break;
case BUDDY_PROP_LOCAL_ALIAS:
g_value_set_string(value, purple_buddy_get_local_alias(buddy));
break;
case BUDDY_PROP_SERVER_ALIAS:
g_value_set_string(value, purple_buddy_get_server_alias(buddy));
break;
case BUDDY_PROP_ICON:
g_value_set_pointer(value, purple_buddy_get_icon(buddy));
break;
case BUDDY_PROP_ACCOUNT:
g_value_set_object(value, purple_buddy_get_account(buddy));
break;
case BUDDY_PROP_PRESENCE:
g_value_set_object(value, purple_buddy_get_presence(buddy));
break;
case BUDDY_PROP_MEDIA_CAPS:
g_value_set_enum(value, purple_buddy_get_media_caps(buddy));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* GObject initialization function */
static void
purple_buddy_init(GTypeInstance *instance, gpointer klass)
{
PURPLE_DBUS_REGISTER_POINTER(PURPLE_BUDDY(instance), PurpleBuddy);
}
/* Called when done constructing */
static void
purple_buddy_constructed(GObject *object)
{
PurpleBuddy *buddy = PURPLE_BUDDY(object);
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(buddy);
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
G_OBJECT_CLASS(blistnode_parent_class)->constructed(object);
priv->presence = PURPLE_PRESENCE(purple_buddy_presence_new(buddy));
purple_presence_set_status_active(priv->presence, "offline", TRUE);
if (ops && ops->new_node)
ops->new_node((PurpleBlistNode *)buddy);
priv->is_constructed = TRUE;
}
/* GObject dispose function */
static void
purple_buddy_dispose(GObject *object)
{
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(object);
if (priv->icon) {
purple_buddy_icon_unref(priv->icon);
priv->icon = NULL;
}
if (priv->presence) {
g_object_unref(priv->presence);
priv->presence = NULL;
}
G_OBJECT_CLASS(blistnode_parent_class)->dispose(object);
}
/* GObject finalize function */
static void
purple_buddy_finalize(GObject *object)
{
PurpleBuddy *buddy = PURPLE_BUDDY(object);
PurpleBuddyPrivate *priv = PURPLE_BUDDY_GET_PRIVATE(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(priv->account));
if (prpl) {
prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
if (prpl_info && prpl_info->buddy_free)
prpl_info->buddy_free(buddy);
}
g_free(priv->name);
g_free(priv->local_alias);
g_free(priv->server_alias);
PURPLE_DBUS_UNREGISTER_POINTER(buddy);
G_OBJECT_CLASS(blistnode_parent_class)->finalize(object);
}
/* Class initializer function */
static void purple_buddy_class_init(PurpleBuddyClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
blistnode_parent_class = g_type_class_peek_parent(klass);
obj_class->dispose = purple_buddy_dispose;
obj_class->finalize = purple_buddy_finalize;
/* Setup properties */
obj_class->get_property = purple_buddy_get_property;
obj_class->set_property = purple_buddy_set_property;
obj_class->constructed = purple_buddy_constructed;
g_type_class_add_private(klass, sizeof(PurpleBuddyPrivate));
bd_properties[BUDDY_PROP_NAME] = g_param_spec_string("name", "Name",
"The name of the buddy.", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
bd_properties[BUDDY_PROP_LOCAL_ALIAS] = g_param_spec_string("local-alias",
"Local alias",
"Local alias of thee buddy.", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
bd_properties[BUDDY_PROP_SERVER_ALIAS] = g_param_spec_string("server-alias",
"Server alias",
"Server-side alias of the buddy.", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
bd_properties[BUDDY_PROP_ICON] = g_param_spec_pointer("icon", "Buddy icon",
"The icon for the buddy.",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
bd_properties[BUDDY_PROP_ACCOUNT] = g_param_spec_object("account",
"Account",
"The account for the buddy.", PURPLE_TYPE_ACCOUNT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
bd_properties[BUDDY_PROP_PRESENCE] = g_param_spec_object("presence",
"Presence",
"The status information for the buddy.", PURPLE_TYPE_PRESENCE,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
bd_properties[BUDDY_PROP_MEDIA_CAPS] = g_param_spec_enum("media-caps",
"Media capabilities",
"The media capabilities of the buddy.",
PURPLE_MEDIA_TYPE_CAPS, PURPLE_MEDIA_CAPS_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, BUDDY_PROP_LAST,
bd_properties);
}
GType
purple_buddy_get_type(void)
{
static GType type = 0;
if(type == 0) {
static const GTypeInfo info = {
sizeof(PurpleBuddyClass),
NULL,
NULL,
(GClassInitFunc)purple_buddy_class_init,
NULL,
NULL,
sizeof(PurpleBuddy),
0,
(GInstanceInitFunc)purple_buddy_init,
NULL,
};
type = g_type_register_static(PURPLE_TYPE_BLIST_NODE,
"PurpleBuddy",
&info, 0);
}
return type;
}
PurpleBuddy *
purple_buddy_new(PurpleAccount *account, const char *name, const char *alias)
{
g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
g_return_val_if_fail(name != NULL, NULL);
return g_object_new(PURPLE_TYPE_BUDDY,
"account", account,
"name", name,
"local-alias", alias,
NULL);
}
/**************************************************************************/
/* Contact API */
/**************************************************************************/
static void
purple_contact_compute_priority_buddy(PurpleContact *contact)
{
PurpleBlistNode *bnode;
PurpleBuddy *new_priority = NULL;
PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
g_return_if_fail(priv != NULL);
priv->priority_buddy = NULL;
for (bnode = PURPLE_BLIST_NODE(contact)->child;
bnode != NULL;
bnode = bnode->next)
{
PurpleBuddy *buddy;
if (!PURPLE_IS_BUDDY(bnode))
continue;
buddy = PURPLE_BUDDY(bnode);
if (new_priority == NULL)
{
new_priority = buddy;
continue;
}
if (purple_account_is_connected(purple_buddy_get_account(buddy)))
{
int cmp = 1;
if (purple_account_is_connected(purple_buddy_get_account(new_priority)))
cmp = purple_buddy_presence_compare(
PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(new_priority)),
PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(buddy)));
if (cmp > 0 || (cmp == 0 &&
purple_prefs_get_bool("/purple/contact/last_match")))
{
new_priority = buddy;
}
}
}
priv->priority_buddy = new_priority;
priv->priority_valid = TRUE;
g_object_notify_by_pspec(G_OBJECT(contact),
co_properties[CONTACT_PROP_PRIORITY_BUDDY]);
}
PurpleGroup *
purple_contact_get_group(const PurpleContact *contact)
{
g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
return PURPLE_GROUP(PURPLE_BLIST_NODE(contact)->parent);
}
void
purple_contact_set_alias(PurpleContact *contact, const char *alias)
{
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
PurpleIMConversation *im;
PurpleBlistNode *bnode;
char *old_alias;
char *new_alias = NULL;
PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
g_return_if_fail(priv != NULL);
if ((alias != NULL) && (*alias != '\0'))
new_alias = purple_utf8_strip_unprintables(alias);
if (!purple_strings_are_different(priv->alias, new_alias)) {
g_free(new_alias);
return;
}
old_alias = priv->alias;
if ((new_alias != NULL) && (*new_alias != '\0'))
priv->alias = new_alias;
else {
priv->alias = NULL;
g_free(new_alias); /* could be "\0" */
}
g_object_notify_by_pspec(G_OBJECT(contact),
co_properties[CONTACT_PROP_ALIAS]);
if (ops) {
if (ops->save_node)
ops->save_node(PURPLE_BLIST_NODE(contact));
if (ops->update)
ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(contact));
}
for(bnode = PURPLE_BLIST_NODE(contact)->child; bnode != NULL; bnode = bnode->next)
{
PurpleBuddy *buddy = PURPLE_BUDDY(bnode);
im = purple_conversations_find_im_with_account(purple_buddy_get_name(buddy),
purple_buddy_get_account(buddy));
if (im)
purple_conversation_autoset_title(PURPLE_CONVERSATION(im));
}
purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
contact, old_alias);
g_free(old_alias);
}
const char *purple_contact_get_alias(PurpleContact* contact)
{
PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
g_return_val_if_fail(priv != NULL, NULL);
if (priv->alias)
return priv->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(PURPLE_IS_CONTACT(c), FALSE);
g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), FALSE);
for (bnode = cnode->child; bnode; bnode = bnode->next) {
PurpleBuddy *buddy;
if (! PURPLE_IS_BUDDY(bnode))
continue;
buddy = (PurpleBuddy *)bnode;
if (purple_buddy_get_account(buddy) == account)
return TRUE;
}
return FALSE;
}
void purple_contact_invalidate_priority_buddy(PurpleContact *contact)
{
PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
g_return_if_fail(priv != NULL);
priv->priority_valid = FALSE;
}
PurpleBuddy *purple_contact_get_priority_buddy(PurpleContact *contact)
{
PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
g_return_val_if_fail(priv != NULL, NULL);
if (!priv->priority_valid)
purple_contact_compute_priority_buddy(contact);
return priv->priority_buddy;
}
void purple_contact_merge(PurpleContact *source, PurpleBlistNode *node)
{
PurpleBlistNode *sourcenode = (PurpleBlistNode*)source;
PurpleBlistNode *prev, *cur, *next;
PurpleContact *target;
g_return_if_fail(PURPLE_IS_CONTACT(source));
g_return_if_fail(PURPLE_IS_BLIST_NODE(node));
if (PURPLE_IS_CONTACT(node)) {
target = (PurpleContact *)node;
prev = _purple_blist_get_last_child(node);
} else if (PURPLE_IS_BUDDY(node)) {
target = (PurpleContact *)node->parent;
prev = node;
} else {
return;
}
if (source == target || !target)
return;
next = sourcenode->child;
while (next) {
cur = next;
next = cur->next;
if (PURPLE_IS_BUDDY(cur)) {
purple_blist_add_buddy((PurpleBuddy *)cur, target, NULL, prev);
prev = cur;
}
}
}
/**************************************************************************
* GObject code for PurpleContact
**************************************************************************/
/* Set method for GObject properties */
static void
purple_contact_set_property(GObject *obj, guint param_id, const GValue *value,
GParamSpec *pspec)
{
PurpleContact *contact = PURPLE_CONTACT(obj);
switch (param_id) {
case CONTACT_PROP_ALIAS:
purple_contact_set_alias(contact, g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* Get method for GObject properties */
static void
purple_contact_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *pspec)
{
PurpleContact *contact = PURPLE_CONTACT(obj);
PurpleContactPrivate *priv = PURPLE_CONTACT_GET_PRIVATE(contact);
switch (param_id) {
case CONTACT_PROP_ALIAS:
g_value_set_string(value, priv->alias);
break;
case CONTACT_PROP_PRIORITY_BUDDY:
g_value_set_object(value, purple_contact_get_priority_buddy(contact));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* GObject initialization function */
static void
purple_contact_init(GTypeInstance *instance, gpointer klass)
{
PurpleContact *contact = PURPLE_CONTACT(instance);
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
if (ops && ops->new_node)
ops->new_node(PURPLE_BLIST_NODE(contact));
PURPLE_DBUS_REGISTER_POINTER(contact, PurpleContact);
}
/* GObject finalize function */
static void
purple_contact_finalize(GObject *object)
{
g_free(PURPLE_CONTACT_GET_PRIVATE(object)->alias);
PURPLE_DBUS_UNREGISTER_POINTER(object);
G_OBJECT_CLASS(counting_parent_class)->finalize(object);
}
/* Class initializer function */
static void purple_contact_class_init(PurpleContactClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
counting_parent_class = g_type_class_peek_parent(klass);
obj_class->finalize = purple_contact_finalize;
/* Setup properties */
obj_class->get_property = purple_contact_get_property;
obj_class->set_property = purple_contact_set_property;
g_type_class_add_private(klass, sizeof(PurpleContactPrivate));
co_properties[CONTACT_PROP_ALIAS] = g_param_spec_string("alias", "Alias",
"The alias for the contact.", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
co_properties[CONTACT_PROP_PRIORITY_BUDDY] = g_param_spec_object(
"priority-buddy",
"Priority buddy", "The priority buddy of the contact.",
PURPLE_TYPE_BUDDY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, CONTACT_PROP_LAST,
co_properties);
}
GType
purple_contact_get_type(void)
{
static GType type = 0;
if(type == 0) {
static const GTypeInfo info = {
sizeof(PurpleContactClass),
NULL,
NULL,
(GClassInitFunc)purple_contact_class_init,
NULL,
NULL,
sizeof(PurpleContact),
0,
(GInstanceInitFunc)purple_contact_init,
NULL,
};
type = g_type_register_static(PURPLE_TYPE_COUNTING_NODE,
"PurpleContact",
&info, 0);
}
return type;
}
PurpleContact *
purple_contact_new(void)
{
return g_object_new(PURPLE_TYPE_CONTACT, NULL);
}
/**************************************************************************/
/* Chat API */
/**************************************************************************/
const char *purple_chat_get_name(PurpleChat *chat)
{
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
g_return_val_if_fail(priv != NULL, NULL);
if ((priv->alias != NULL) && (*priv->alias != '\0'))
return priv->alias;
return purple_chat_get_name_only(chat);
}
const char *purple_chat_get_name_only(PurpleChat *chat)
{
char *ret = NULL;
PurplePlugin *prpl;
PurplePluginProtocolInfo *prpl_info = NULL;
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
g_return_val_if_fail(priv != NULL, NULL);
prpl = purple_find_prpl(purple_account_get_protocol_id(priv->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(priv->account));
pce = parts->data;
ret = g_hash_table_lookup(priv->components, pce->identifier);
g_list_foreach(parts, (GFunc)g_free, NULL);
g_list_free(parts);
}
return ret;
}
void
purple_chat_set_alias(PurpleChat *chat, const char *alias)
{
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
char *old_alias;
char *new_alias = NULL;
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
g_return_if_fail(priv != NULL);
if ((alias != NULL) && (*alias != '\0'))
new_alias = purple_utf8_strip_unprintables(alias);
if (!purple_strings_are_different(priv->alias, new_alias)) {
g_free(new_alias);
return;
}
old_alias = priv->alias;
if ((new_alias != NULL) && (*new_alias != '\0'))
priv->alias = new_alias;
else {
priv->alias = NULL;
g_free(new_alias); /* could be "\0" */
}
g_object_notify_by_pspec(G_OBJECT(chat), ch_properties[CHAT_PROP_ALIAS]);
if (ops) {
if (ops->save_node)
ops->save_node(PURPLE_BLIST_NODE(chat));
if (ops->update)
ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(chat));
}
purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased",
chat, old_alias);
g_free(old_alias);
}
PurpleGroup *
purple_chat_get_group(PurpleChat *chat)
{
g_return_val_if_fail(PURPLE_IS_CHAT(chat), NULL);
return PURPLE_GROUP(PURPLE_BLIST_NODE(chat)->parent);
}
PurpleAccount *
purple_chat_get_account(PurpleChat *chat)
{
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
g_return_val_if_fail(priv != NULL, NULL);
return priv->account;
}
GHashTable *
purple_chat_get_components(PurpleChat *chat)
{
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
g_return_val_if_fail(priv != NULL, NULL);
return priv->components;
}
/**************************************************************************
* GObject code for PurpleChat
**************************************************************************/
/* Set method for GObject properties */
static void
purple_chat_set_property(GObject *obj, guint param_id, const GValue *value,
GParamSpec *pspec)
{
PurpleChat *chat = PURPLE_CHAT(obj);
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
switch (param_id) {
case CHAT_PROP_ALIAS:
if (priv->is_constructed)
purple_chat_set_alias(chat, g_value_get_string(value));
else
priv->alias =
purple_utf8_strip_unprintables(g_value_get_string(value));
break;
case CHAT_PROP_ACCOUNT:
priv->account = g_value_get_object(value);
break;
case CHAT_PROP_COMPONENTS:
priv->components = g_value_get_pointer(value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* Get method for GObject properties */
static void
purple_chat_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *pspec)
{
PurpleChat *chat = PURPLE_CHAT(obj);
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
switch (param_id) {
case CHAT_PROP_ALIAS:
g_value_set_string(value, priv->alias);
break;
case CHAT_PROP_ACCOUNT:
g_value_set_object(value, purple_chat_get_account(chat));
break;
case CHAT_PROP_COMPONENTS:
g_value_set_pointer(value, purple_chat_get_components(chat));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* GObject initialization function */
static void
purple_chat_init(GTypeInstance *instance, gpointer klass)
{
PURPLE_DBUS_REGISTER_POINTER(PURPLE_CHAT(instance), PurpleChat);
}
/* Called when done constructing */
static void
purple_chat_constructed(GObject *object)
{
PurpleChat *chat = PURPLE_CHAT(object);
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(chat);
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
G_OBJECT_CLASS(blistnode_parent_class)->constructed(object);
if (ops != NULL && ops->new_node != NULL)
ops->new_node(PURPLE_BLIST_NODE(chat));
priv->is_constructed = TRUE;
}
/* GObject finalize function */
static void
purple_chat_finalize(GObject *object)
{
PurpleChatPrivate *priv = PURPLE_CHAT_GET_PRIVATE(object);
g_free(priv->alias);
g_hash_table_destroy(priv->components);
PURPLE_DBUS_UNREGISTER_POINTER(object);
G_OBJECT_CLASS(blistnode_parent_class)->finalize(object);
}
/* Class initializer function */
static void purple_chat_class_init(PurpleChatClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
blistnode_parent_class = g_type_class_peek_parent(klass);
obj_class->finalize = purple_chat_finalize;
/* Setup properties */
obj_class->get_property = purple_chat_get_property;
obj_class->set_property = purple_chat_set_property;
obj_class->constructed = purple_chat_constructed;
g_type_class_add_private(klass, sizeof(PurpleChatPrivate));
ch_properties[CHAT_PROP_ALIAS] = g_param_spec_string("alias", "Alias",
"The alias for the chat.", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
ch_properties[CHAT_PROP_ACCOUNT] = g_param_spec_object("account", "Account",
"The account that the chat belongs to.", PURPLE_TYPE_ACCOUNT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
ch_properties[CHAT_PROP_COMPONENTS] = g_param_spec_pointer("components",
"Components",
"The protocol components of the chat.",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, CHAT_PROP_LAST, ch_properties);
}
GType
purple_chat_get_type(void)
{
static GType type = 0;
if(type == 0) {
static const GTypeInfo info = {
sizeof(PurpleChatClass),
NULL,
NULL,
(GClassInitFunc)purple_chat_class_init,
NULL,
NULL,
sizeof(PurpleChat),
0,
(GInstanceInitFunc)purple_chat_init,
NULL,
};
type = g_type_register_static(PURPLE_TYPE_BLIST_NODE,
"PurpleChat",
&info, 0);
}
return type;
}
PurpleChat *
purple_chat_new(PurpleAccount *account, const char *alias, GHashTable *components)
{
g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
g_return_val_if_fail(components != NULL, NULL);
return g_object_new(PURPLE_TYPE_CHAT,
"account", account,
"alias", alias,
"components", components,
NULL);
}
/**************************************************************************/
/* Group API */
/**************************************************************************/
GSList *purple_group_get_accounts(PurpleGroup *group)
{
GSList *l = NULL;
PurpleBlistNode *gnode, *cnode, *bnode;
gnode = (PurpleBlistNode *)group;
for (cnode = gnode->child; cnode; cnode = cnode->next) {
if (PURPLE_IS_CHAT(cnode)) {
if (!g_slist_find(l, purple_chat_get_account(PURPLE_CHAT(cnode))))
l = g_slist_append(l, purple_chat_get_account(PURPLE_CHAT(cnode)));
} else if (PURPLE_IS_CONTACT(cnode)) {
for (bnode = cnode->child; bnode; bnode = bnode->next) {
if (PURPLE_IS_BUDDY(bnode)) {
if (!g_slist_find(l, purple_buddy_get_account(PURPLE_BUDDY(bnode))))
l = g_slist_append(l, purple_buddy_get_account(PURPLE_BUDDY(bnode)));
}
}
}
}
return l;
}
gboolean purple_group_on_account(PurpleGroup *g, PurpleAccount *account)
{
PurpleBlistNode *cnode;
for (cnode = ((PurpleBlistNode *)g)->child; cnode; cnode = cnode->next) {
if (PURPLE_IS_CONTACT(cnode)) {
if(purple_contact_on_account((PurpleContact *) cnode, account))
return TRUE;
} else if (PURPLE_IS_CHAT(cnode)) {
PurpleChat *chat = (PurpleChat *)cnode;
if ((!account && purple_account_is_connected(purple_chat_get_account(chat)))
|| purple_chat_get_account(chat) == account)
return TRUE;
}
}
return FALSE;
}
/*
* TODO: If merging, prompt the user if they want to merge.
*/
void purple_group_set_name(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;
PurpleGroupPrivate *priv = PURPLE_GROUP_GET_PRIVATE(source);
g_return_if_fail(priv != NULL);
g_return_if_fail(name != NULL);
new_name = purple_utf8_strip_unprintables(name);
if (*new_name == '\0' || purple_strequal(new_name, priv->name)) {
g_free(new_name);
return;
}
dest = purple_blist_find_group(new_name);
if (dest != NULL && purple_utf8_strcasecmp(priv->name,
PURPLE_GROUP_GET_PRIVATE(dest)->name) != 0) {
/* We're merging two groups */
PurpleBlistNode *prev, *child, *next;
prev = _purple_blist_get_last_child((PurpleBlistNode*)dest);
child = PURPLE_BLIST_NODE(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_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_IS_CHAT(child)) {
purple_blist_add_chat((PurpleChat *)child, dest, prev);
prev = child;
} else {
purple_debug(PURPLE_DEBUG_ERROR, "blistnodetypes",
"Unknown child type in group %s\n", priv->name);
}
child = next;
}
/* Make a copy of the old group name and then delete the old group */
old_name = g_strdup(priv->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 = PURPLE_BLIST_NODE(source)->child; cnode != NULL; cnode = cnode->next) {
if (PURPLE_IS_CONTACT(cnode))
for (bnode = cnode->child; bnode != NULL; bnode = bnode->next)
moved_buddies = g_list_append(moved_buddies, bnode);
}
purple_blist_update_groups_cache(source, new_name);
old_name = priv->name;
priv->name = new_name;
g_object_notify_by_pspec(G_OBJECT(source), gr_properties[GROUP_PROP_NAME]);
}
/* Save our changes */
if (ops && ops->save_node)
ops->save_node(PURPLE_BLIST_NODE(source));
/* Update the UI */
if (ops && ops->update)
ops->update(purple_blist_get_buddy_list(), PURPLE_BLIST_NODE(source));
/* Notify all PRPLs */
/* TODO: Is this condition needed? Seems like it would always be TRUE */
if(old_name && !purple_strequal(priv->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 = PURPLE_BUDDY(l->data);
if(buddy && purple_buddy_get_account(buddy) == 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, NULL);
}
g_list_free(buddies);
}
}
g_list_free(moved_buddies);
g_free(old_name);
g_object_notify_by_pspec(G_OBJECT(source), gr_properties[GROUP_PROP_NAME]);
}
const char *purple_group_get_name(PurpleGroup *group)
{
PurpleGroupPrivate *priv = PURPLE_GROUP_GET_PRIVATE(group);
g_return_val_if_fail(priv != NULL, NULL);
return priv->name;
}
/**************************************************************************
* GObject code for PurpleGroup
**************************************************************************/
/* Set method for GObject properties */
static void
purple_group_set_property(GObject *obj, guint param_id, const GValue *value,
GParamSpec *pspec)
{
PurpleGroup *group = PURPLE_GROUP(obj);
PurpleGroupPrivate *priv = PURPLE_GROUP_GET_PRIVATE(group);
switch (param_id) {
case GROUP_PROP_NAME:
if (priv->is_constructed)
purple_group_set_name(group, g_value_get_string(value));
else
priv->name =
purple_utf8_strip_unprintables(g_value_get_string(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* Get method for GObject properties */
static void
purple_group_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *pspec)
{
PurpleGroup *group = PURPLE_GROUP(obj);
switch (param_id) {
case GROUP_PROP_NAME:
g_value_set_string(value, purple_group_get_name(group));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* GObject initialization function */
static void
purple_group_init(GTypeInstance *instance, gpointer klass)
{
PURPLE_DBUS_REGISTER_POINTER(PURPLE_GROUP(instance), PurpleGroup);
}
/* Called when done constructing */
static void
purple_group_constructed(GObject *object)
{
PurpleGroup *group = PURPLE_GROUP(object);
PurpleGroupPrivate *priv = PURPLE_GROUP_GET_PRIVATE(group);
PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
G_OBJECT_CLASS(counting_parent_class)->constructed(object);
if (ops && ops->new_node)
ops->new_node(PURPLE_BLIST_NODE(group));
priv->is_constructed = TRUE;
}
/* GObject finalize function */
static void
purple_group_finalize(GObject *object)
{
g_free(PURPLE_GROUP_GET_PRIVATE(object)->name);
PURPLE_DBUS_UNREGISTER_POINTER(object);
G_OBJECT_CLASS(counting_parent_class)->finalize(object);
}
/* Class initializer function */
static void purple_group_class_init(PurpleGroupClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
counting_parent_class = g_type_class_peek_parent(klass);
obj_class->finalize = purple_group_finalize;
obj_class->constructed = purple_group_constructed;
/* Setup properties */
obj_class->get_property = purple_group_get_property;
obj_class->set_property = purple_group_set_property;
g_type_class_add_private(klass, sizeof(PurpleGroupPrivate));
gr_properties[GROUP_PROP_NAME] = g_param_spec_string("name", "Name",
"Name of the group.", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, GROUP_PROP_LAST,
gr_properties);
}
GType
purple_group_get_type(void)
{
static GType type = 0;
if(type == 0) {
static const GTypeInfo info = {
sizeof(PurpleGroupClass),
NULL,
NULL,
(GClassInitFunc)purple_group_class_init,
NULL,
NULL,
sizeof(PurpleGroup),
0,
(GInstanceInitFunc)purple_group_init,
NULL,
};
type = g_type_register_static(PURPLE_TYPE_COUNTING_NODE,
"PurpleGroup",
&info, 0);
}
return type;
}
PurpleGroup *
purple_group_new(const char *name)
{
PurpleGroup *group;
g_return_val_if_fail(name != NULL, NULL);
g_return_val_if_fail(*name != '\0', NULL);
group = purple_blist_find_group(name);
if (group != NULL)
return group;
return g_object_new(PURPLE_TYPE_GROUP, "name", name, NULL);
}