* Purple is the legal property of its developers, whose names are too numerous * to list here. Please refer to the COPYRIGHT file distributed with this * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA typedef struct _PurpleBuddyPrivate PurpleBuddyPrivate; 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 protocol 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 /****************************************************************************** *****************************************************************************/ static GParamSpec *properties[PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddy, purple_buddy, PURPLE_TYPE_BLIST_NODE) /****************************************************************************** *****************************************************************************/ purple_buddy_set_icon(PurpleBuddy *buddy, PurpleBuddyIcon *icon) PurpleBuddyPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_BUDDY(buddy)); priv = purple_buddy_get_instance_private(buddy); purple_buddy_icon_unref(priv->icon); priv->icon = (icon != NULL ? purple_buddy_icon_ref(icon) : NULL); g_object_notify_by_pspec(G_OBJECT(buddy), purple_signal_emit(purple_blist_get_handle(), "buddy-icon-changed", buddy); purple_blist_update_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); purple_buddy_get_icon(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); purple_buddy_get_account(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); purple_buddy_set_name(PurpleBuddy *buddy, const char *name) PurpleBuddyPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_BUDDY(buddy)); priv = purple_buddy_get_instance_private(buddy); purple_blist_update_buddies_cache(buddy, name); priv->name = purple_utf8_strip_unprintables(name); g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_NAME]); purple_blist_save_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); purple_blist_update_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); purple_buddy_get_name(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); purple_buddy_get_protocol_data(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); purple_buddy_set_protocol_data(PurpleBuddy *buddy, gpointer data) PurpleBuddyPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_BUDDY(buddy)); priv = purple_buddy_get_instance_private(buddy); const char *purple_buddy_get_alias_only(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); 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; const char *purple_buddy_get_contact_alias(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); /* Search for an alias for the buddy. In order of precedence: */ /* The local buddy alias */ if (priv->local_alias != NULL) return priv->local_alias; c = purple_buddy_get_contact(buddy); if ((c != NULL) && (purple_contact_get_alias(c) != NULL)) return purple_contact_get_alias(c); if ((priv->server_alias) && (*priv->server_alias)) return priv->server_alias; /* The buddy's user name (i.e. no alias) */ const char *purple_buddy_get_alias(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); /* Search for an alias for the buddy. In order of precedence: */ if (priv->local_alias != NULL) return priv->local_alias; if ((priv->server_alias) && (*priv->server_alias)) return priv->server_alias; /* The buddy's user name (i.e. no alias) */ purple_buddy_set_local_alias(PurpleBuddy *buddy, const char *alias) PurpleBuddyPrivate *priv = NULL; PurpleIMConversation *im; g_return_if_fail(PURPLE_IS_BUDDY(buddy)); priv = purple_buddy_get_instance_private(buddy); if ((alias != NULL) && (*alias != '\0')) new_alias = purple_utf8_strip_unprintables(alias); if (purple_strequal(priv->local_alias, new_alias)) { old_alias = priv->local_alias; if ((new_alias != NULL) && (*new_alias != '\0')) priv->local_alias = new_alias; priv->local_alias = NULL; g_free(new_alias); /* could be "\0" */ g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_LOCAL_ALIAS]); purple_blist_save_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); purple_blist_update_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); im = purple_conversations_find_im_with_account(priv->name, purple_conversation_autoset_title(PURPLE_CONVERSATION(im)); purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased", const char *purple_buddy_get_local_alias(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); return priv->local_alias; purple_buddy_set_server_alias(PurpleBuddy *buddy, const char *alias) PurpleBuddyPrivate *priv = NULL; PurpleIMConversation *im; g_return_if_fail(PURPLE_IS_BUDDY(buddy)); priv = purple_buddy_get_instance_private(buddy); if ((alias != NULL) && (*alias != '\0') && g_utf8_validate(alias, -1, NULL)) new_alias = purple_utf8_strip_unprintables(alias); if (purple_strequal(priv->server_alias, new_alias)) { old_alias = priv->server_alias; if ((new_alias != NULL) && (*new_alias != '\0')) priv->server_alias = new_alias; priv->server_alias = NULL; g_free(new_alias); /* could be "\0"; */ g_object_notify_by_pspec(G_OBJECT(buddy), properties[PROP_SERVER_ALIAS]); purple_blist_save_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); purple_blist_update_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); im = purple_conversations_find_im_with_account(priv->name, purple_conversation_autoset_title(PURPLE_CONVERSATION(im)); purple_signal_emit(purple_blist_get_handle(), "blist-node-aliased", const char *purple_buddy_get_server_alias(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); if ((priv->server_alias) && (*priv->server_alias)) return priv->server_alias; 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(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); priv = purple_buddy_get_instance_private(buddy); purple_buddy_update_status(PurpleBuddy *buddy, PurpleStatus *old_status) PurpleBuddyPrivate *priv = NULL; PurpleCountingNode *contact_counter, *group_counter; g_return_if_fail(PURPLE_IS_BUDDY(buddy)); priv = purple_buddy_get_instance_private(buddy); 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); purple_signal_emit(purple_blist_get_handle(), "buddy-status-changed", buddy, old_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)); purple_blist_update_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); PurpleMediaCaps purple_buddy_get_media_caps(PurpleBuddy *buddy) PurpleBuddyPrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), 0); priv = purple_buddy_get_instance_private(buddy); void purple_buddy_set_media_caps(PurpleBuddy *buddy, PurpleMediaCaps media_caps) PurpleBuddyPrivate *priv = NULL; g_return_if_fail(PURPLE_IS_BUDDY(buddy)); priv = purple_buddy_get_instance_private(buddy); priv->media_caps = media_caps; g_object_notify_by_pspec(G_OBJECT(buddy), properties[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 purple_blist_get_default_group(); return PURPLE_GROUP(PURPLE_BLIST_NODE(buddy)->parent->parent); /****************************************************************************** *****************************************************************************/ purple_buddy_set_property(GObject *obj, guint param_id, const GValue *value, PurpleBuddy *buddy = PURPLE_BUDDY(obj); PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(buddy); if (priv->is_constructed) purple_buddy_set_name(buddy, g_value_get_string(value)); purple_utf8_strip_unprintables(g_value_get_string(value)); if (priv->is_constructed) purple_buddy_set_local_alias(buddy, g_value_get_string(value)); purple_utf8_strip_unprintables(g_value_get_string(value)); purple_buddy_set_server_alias(buddy, g_value_get_string(value)); purple_buddy_set_icon(buddy, g_value_get_pointer(value)); priv->account = g_value_get_object(value); purple_buddy_set_media_caps(buddy, g_value_get_enum(value)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); purple_buddy_get_property(GObject *obj, guint param_id, GValue *value, PurpleBuddy *buddy = PURPLE_BUDDY(obj); g_value_set_string(value, purple_buddy_get_name(buddy)); g_value_set_string(value, purple_buddy_get_local_alias(buddy)); g_value_set_string(value, purple_buddy_get_server_alias(buddy)); g_value_set_pointer(value, purple_buddy_get_icon(buddy)); g_value_set_object(value, purple_buddy_get_account(buddy)); g_value_set_object(value, purple_buddy_get_presence(buddy)); g_value_set_enum(value, purple_buddy_get_media_caps(buddy)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); purple_buddy_init(PurpleBuddy *buddy) purple_buddy_constructed(GObject *object) { PurpleBuddy *buddy = PURPLE_BUDDY(object); PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(buddy); G_OBJECT_CLASS(purple_buddy_parent_class)->constructed(object); priv->presence = PURPLE_PRESENCE(purple_buddy_presence_new(buddy)); purple_presence_set_status_active(priv->presence, "offline", TRUE); purple_blist_new_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); priv->is_constructed = TRUE; purple_buddy_dispose(GObject *object) { PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(PURPLE_BUDDY(object)); purple_buddy_icon_unref(priv->icon); g_object_unref(priv->presence); G_OBJECT_CLASS(purple_buddy_parent_class)->dispose(object); purple_buddy_finalize(GObject *object) { PurpleBuddy *buddy = PURPLE_BUDDY(object); PurpleBuddyPrivate *priv = purple_buddy_get_instance_private(buddy); PurpleProtocol *protocol; * Tell the owner protocol that we're about to free the buddy so it protocol = purple_protocols_find(purple_account_get_protocol_id(priv->account)); purple_protocol_client_iface_buddy_free(protocol, buddy); g_free(priv->local_alias); g_free(priv->server_alias); G_OBJECT_CLASS(purple_buddy_parent_class)->finalize(object); static void purple_buddy_class_init(PurpleBuddyClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->dispose = purple_buddy_dispose; obj_class->finalize = purple_buddy_finalize; obj_class->get_property = purple_buddy_get_property; obj_class->set_property = purple_buddy_set_property; obj_class->constructed = purple_buddy_constructed; properties[PROP_NAME] = g_param_spec_string( "The name of the buddy.", G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS properties[PROP_LOCAL_ALIAS] = g_param_spec_string( "Local alias of thee buddy.", G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS properties[PROP_SERVER_ALIAS] = g_param_spec_string( "Server-side alias of the buddy.", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS properties[PROP_ICON] = g_param_spec_pointer( "The icon for the buddy.", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS properties[PROP_ACCOUNT] = g_param_spec_object( "The account for the buddy.", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS properties[PROP_PRESENCE] = g_param_spec_object( "The status information for the buddy.", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS properties[PROP_MEDIA_CAPS] = g_param_spec_enum( "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, PROP_LAST, properties); 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,