Mon, 11 Nov 2019 20:43:31 -0600
closing merged branch
/* 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 "debug.h" #include "presence.h" /************************************************************************** * PurplePresence **************************************************************************/ /** Private data for a presence */ typedef struct { gboolean idle; time_t idle_time; time_t login_time; GList *statuses; GHashTable *status_table; PurpleStatus *active_status; } PurplePresencePrivate; /* Presence property enums */ enum { PRES_PROP_0, PRES_PROP_IDLE, PRES_PROP_IDLE_TIME, PRES_PROP_LOGIN_TIME, PRES_PROP_STATUSES, PRES_PROP_ACTIVE_STATUS, PRES_PROP_LAST }; static GParamSpec *properties[PRES_PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurplePresence, purple_presence, G_TYPE_OBJECT) /************************************************************************** * PurpleAccountPresence **************************************************************************/ /** * PurpleAccountPresence: * * A presence for an account */ struct _PurpleAccountPresence { PurplePresence parent; }; /** Private data for an account presence */ typedef struct { PurpleAccount *account; } PurpleAccountPresencePrivate; /* Account presence property enums */ enum { ACPRES_PROP_0, ACPRES_PROP_ACCOUNT, ACPRES_PROP_LAST }; static GParamSpec *ap_properties[ACPRES_PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurpleAccountPresence, purple_account_presence, PURPLE_TYPE_PRESENCE) /************************************************************************** * PurpleBuddyPresence **************************************************************************/ /** * PurpleBuddyPresence: * * A presence for a buddy */ struct _PurpleBuddyPresence { PurplePresence parent; }; /** Private data for a buddy presence */ typedef struct { PurpleBuddy *buddy; } PurpleBuddyPresencePrivate; /* Buddy presence property enums */ enum { BUDPRES_PROP_0, BUDPRES_PROP_BUDDY, BUDPRES_PROP_LAST }; static GParamSpec *bp_properties[BUDPRES_PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddyPresence, purple_buddy_presence, PURPLE_TYPE_PRESENCE) /************************************************************************** * PurplePresence API **************************************************************************/ void purple_presence_set_status_active(PurplePresence *presence, const char *status_id, gboolean active) { PurpleStatus *status; g_return_if_fail(PURPLE_IS_PRESENCE(presence)); g_return_if_fail(status_id != NULL); status = purple_presence_get_status(presence, status_id); g_return_if_fail(PURPLE_IS_STATUS(status)); /* TODO: Should we do the following? */ /* g_return_if_fail(active == status->active); */ if (purple_status_is_exclusive(status)) { if (!active) { purple_debug_warning("presence", "Attempted to set a non-independent status " "(%s) inactive. Only independent statuses " "can be specifically marked inactive.", status_id); return; } } purple_status_set_active(status, active); } void purple_presence_switch_status(PurplePresence *presence, const char *status_id) { purple_presence_set_status_active(presence, status_id, TRUE); } void purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time) { PurplePresencePrivate *priv = NULL; PurplePresenceClass *klass = NULL; gboolean old_idle; GObject *obj; g_return_if_fail(PURPLE_IS_PRESENCE(presence)); priv = purple_presence_get_instance_private(presence); klass = PURPLE_PRESENCE_GET_CLASS(presence); if (priv->idle == idle && priv->idle_time == idle_time) return; old_idle = priv->idle; priv->idle = idle; priv->idle_time = (idle ? idle_time : 0); obj = G_OBJECT(presence); g_object_freeze_notify(obj); g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE]); g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE_TIME]); g_object_thaw_notify(obj); if (klass->update_idle) klass->update_idle(presence, old_idle); } void purple_presence_set_login_time(PurplePresence *presence, time_t login_time) { PurplePresencePrivate *priv = NULL; g_return_if_fail(PURPLE_IS_PRESENCE(presence)); priv = purple_presence_get_instance_private(presence); if (priv->login_time == login_time) return; priv->login_time = login_time; g_object_notify_by_pspec(G_OBJECT(presence), properties[PRES_PROP_LOGIN_TIME]); } GList * purple_presence_get_statuses(PurplePresence *presence) { PurplePresencePrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL); priv = purple_presence_get_instance_private(presence); return priv->statuses; } PurpleStatus * purple_presence_get_status(PurplePresence *presence, const char *status_id) { PurplePresencePrivate *priv = NULL; PurpleStatus *status; GList *l = NULL; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL); g_return_val_if_fail(status_id != NULL, NULL); priv = purple_presence_get_instance_private(presence); /* What's the purpose of this hash table? */ status = (PurpleStatus *)g_hash_table_lookup(priv->status_table, status_id); if (status == NULL) { for (l = purple_presence_get_statuses(presence); l != NULL && status == NULL; l = l->next) { PurpleStatus *temp_status = l->data; if (purple_strequal(status_id, purple_status_get_id(temp_status))) status = temp_status; } if (status != NULL) g_hash_table_insert(priv->status_table, g_strdup(purple_status_get_id(status)), status); } return status; } PurpleStatus * purple_presence_get_active_status(PurplePresence *presence) { PurplePresencePrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL); priv = purple_presence_get_instance_private(presence); return priv->active_status; } gboolean purple_presence_is_available(PurplePresence *presence) { PurpleStatus *status; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE); status = purple_presence_get_active_status(presence); return ((status != NULL && purple_status_is_available(status)) && !purple_presence_is_idle(presence)); } gboolean purple_presence_is_online(PurplePresence *presence) { PurpleStatus *status; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE); if ((status = purple_presence_get_active_status(presence)) == NULL) return FALSE; return purple_status_is_online(status); } gboolean purple_presence_is_status_active(PurplePresence *presence, const char *status_id) { PurpleStatus *status; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE); g_return_val_if_fail(status_id != NULL, FALSE); status = purple_presence_get_status(presence, status_id); return (status != NULL && purple_status_is_active(status)); } gboolean purple_presence_is_status_primitive_active(PurplePresence *presence, PurpleStatusPrimitive primitive) { GList *l; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE); g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, FALSE); for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) { PurpleStatus *temp_status = l->data; PurpleStatusType *type = purple_status_get_status_type(temp_status); if (purple_status_type_get_primitive(type) == primitive && purple_status_is_active(temp_status)) return TRUE; } return FALSE; } gboolean purple_presence_is_idle(PurplePresence *presence) { PurplePresencePrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE); priv = purple_presence_get_instance_private(presence); return purple_presence_is_online(presence) && priv->idle; } time_t purple_presence_get_idle_time(PurplePresence *presence) { PurplePresencePrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), 0); priv = purple_presence_get_instance_private(presence); return priv->idle_time; } time_t purple_presence_get_login_time(PurplePresence *presence) { PurplePresencePrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), 0); priv = purple_presence_get_instance_private(presence); return purple_presence_is_online(presence) ? priv->login_time : 0; } /************************************************************************** * GObject code for PurplePresence **************************************************************************/ /* Set method for GObject properties */ static void purple_presence_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) { PurplePresence *presence = PURPLE_PRESENCE(obj); PurplePresencePrivate *priv = purple_presence_get_instance_private(presence); switch (param_id) { case PRES_PROP_IDLE: purple_presence_set_idle(presence, g_value_get_boolean(value), 0); break; case PRES_PROP_IDLE_TIME: #if SIZEOF_TIME_T == 4 purple_presence_set_idle(presence, TRUE, g_value_get_int(value)); #elif SIZEOF_TIME_T == 8 purple_presence_set_idle(presence, TRUE, g_value_get_int64(value)); #else #error Unknown size of time_t #endif break; case PRES_PROP_LOGIN_TIME: #if SIZEOF_TIME_T == 4 purple_presence_set_login_time(presence, g_value_get_int(value)); #elif SIZEOF_TIME_T == 8 purple_presence_set_login_time(presence, g_value_get_int64(value)); #else #error Unknown size of time_t #endif break; case PRES_PROP_ACTIVE_STATUS: priv->active_status = g_value_get_object(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } /* Get method for GObject properties */ static void purple_presence_get_property(GObject *obj, guint param_id, GValue *value, GParamSpec *pspec) { PurplePresence *presence = PURPLE_PRESENCE(obj); switch (param_id) { case PRES_PROP_IDLE: g_value_set_boolean(value, purple_presence_is_idle(presence)); break; case PRES_PROP_IDLE_TIME: #if SIZEOF_TIME_T == 4 g_value_set_int(value, purple_presence_get_idle_time(presence)); #elif SIZEOF_TIME_T == 8 g_value_set_int64(value, purple_presence_get_idle_time(presence)); #else #error Unknown size of time_t #endif break; case PRES_PROP_LOGIN_TIME: #if SIZEOF_TIME_T == 4 g_value_set_int(value, purple_presence_get_login_time(presence)); #elif SIZEOF_TIME_T == 8 g_value_set_int64(value, purple_presence_get_login_time(presence)); #else #error Unknown size of time_t #endif break; case PRES_PROP_STATUSES: g_value_set_pointer(value, purple_presence_get_statuses(presence)); break; case PRES_PROP_ACTIVE_STATUS: g_value_set_object(value, purple_presence_get_active_status(presence)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } /* GObject initialization function */ static void purple_presence_init(PurplePresence *presence) { PurplePresencePrivate *priv = purple_presence_get_instance_private(presence); priv->status_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); } /* GObject dispose function */ static void purple_presence_dispose(GObject *object) { PurplePresencePrivate *priv = purple_presence_get_instance_private(PURPLE_PRESENCE(object)); if (priv->statuses) { g_list_free_full(priv->statuses, g_object_unref); priv->statuses = NULL; } G_OBJECT_CLASS(purple_presence_parent_class)->dispose(object); } /* GObject finalize function */ static void purple_presence_finalize(GObject *object) { PurplePresencePrivate *priv = purple_presence_get_instance_private(PURPLE_PRESENCE(object)); g_hash_table_destroy(priv->status_table); G_OBJECT_CLASS(purple_presence_parent_class)->finalize(object); } /* Class initializer function */ static void purple_presence_class_init(PurplePresenceClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); obj_class->dispose = purple_presence_dispose; obj_class->finalize = purple_presence_finalize; /* Setup properties */ obj_class->get_property = purple_presence_get_property; obj_class->set_property = purple_presence_set_property; properties[PRES_PROP_IDLE] = g_param_spec_boolean("idle", "Idle", "Whether the presence is in idle state.", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PRES_PROP_IDLE_TIME] = #if SIZEOF_TIME_T == 4 g_param_spec_int #elif SIZEOF_TIME_T == 8 g_param_spec_int64 #else #error Unknown size of time_t #endif ("idle-time", "Idle time", "The idle time of the presence", #if SIZEOF_TIME_T == 4 G_MININT, G_MAXINT, 0, #elif SIZEOF_TIME_T == 8 G_MININT64, G_MAXINT64, 0, #else #error Unknown size of time_t #endif G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PRES_PROP_LOGIN_TIME] = #if SIZEOF_TIME_T == 4 g_param_spec_int #elif SIZEOF_TIME_T == 8 g_param_spec_int64 #else #error Unknown size of time_t #endif ("login-time", "Login time", "The login time of the presence.", #if SIZEOF_TIME_T == 4 G_MININT, G_MAXINT, 0, #elif SIZEOF_TIME_T == 8 G_MININT64, G_MAXINT64, 0, #else #error Unknown size of time_t #endif G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PRES_PROP_STATUSES] = g_param_spec_pointer("statuses", "Statuses", "The list of statuses in the presence.", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); properties[PRES_PROP_ACTIVE_STATUS] = g_param_spec_object("active-status", "Active status", "The active status for the presence.", PURPLE_TYPE_STATUS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, PRES_PROP_LAST, properties); } /************************************************************************** * PurpleAccountPresence API **************************************************************************/ static void purple_account_presence_update_idle(PurplePresence *presence, gboolean old_idle) { PurpleAccount *account; PurpleConnection *gc = NULL; PurpleProtocol *protocol = NULL; gboolean idle = purple_presence_is_idle(presence); time_t idle_time = purple_presence_get_idle_time(presence); time_t current_time = time(NULL); account = purple_account_presence_get_account(PURPLE_ACCOUNT_PRESENCE(presence)); if (purple_prefs_get_bool("/purple/logging/log_system")) { PurpleLog *log = purple_account_get_log(account, FALSE); if (log != NULL) { char *msg, *tmp; GDateTime *dt; if (idle) { tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account)); dt = g_date_time_new_from_unix_local(idle_time); } else { tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account)); dt = g_date_time_new_now_utc(); } msg = g_markup_escape_text(tmp, -1); g_free(tmp); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_account_get_username(account), dt, msg); g_date_time_unref(dt); g_free(msg); } } gc = purple_account_get_connection(account); if(PURPLE_CONNECTION_IS_CONNECTED(gc)) protocol = purple_connection_get_protocol(gc); if (protocol) purple_protocol_server_iface_set_idle(protocol, gc, (idle ? (current_time - idle_time) : 0)); } PurpleAccount * purple_account_presence_get_account(PurpleAccountPresence *presence) { PurpleAccountPresencePrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_ACCOUNT_PRESENCE(presence), NULL); priv = purple_account_presence_get_instance_private(presence); return priv->account; } static int purple_buddy_presence_compute_score(PurpleBuddyPresence *buddy_presence) { GList *l; int score = 0; PurplePresence *presence = PURPLE_PRESENCE(buddy_presence); PurpleBuddy *b = purple_buddy_presence_get_buddy(buddy_presence); int *primitive_scores = _purple_statuses_get_primitive_scores(); int offline_score = purple_prefs_get_int("/purple/status/scores/offline_msg"); int idle_score = purple_prefs_get_int("/purple/status/scores/idle"); for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) { PurpleStatus *status = (PurpleStatus *)l->data; PurpleStatusType *type = purple_status_get_status_type(status); if (purple_status_is_active(status)) { score += primitive_scores[purple_status_type_get_primitive(type)]; if (!purple_status_is_online(status)) { if (b && purple_account_supports_offline_message(purple_buddy_get_account(b), b)) score += offline_score; } } } score += purple_account_get_int(purple_buddy_get_account(b), "score", 0); if (purple_presence_is_idle(presence)) score += idle_score; return score; } gint purple_buddy_presence_compare(PurpleBuddyPresence *buddy_presence1, PurpleBuddyPresence *buddy_presence2) { PurplePresence *presence1 = PURPLE_PRESENCE(buddy_presence1); PurplePresence *presence2 = PURPLE_PRESENCE(buddy_presence2); time_t idle_time_1, idle_time_2; int score1 = 0, score2 = 0; int idle_time_score = purple_prefs_get_int("/purple/status/scores/idle_time"); if (presence1 == presence2) return 0; else if (presence1 == NULL) return 1; else if (presence2 == NULL) return -1; if (purple_presence_is_online(presence1) && !purple_presence_is_online(presence2)) return -1; else if (purple_presence_is_online(presence2) && !purple_presence_is_online(presence1)) return 1; /* Compute the score of the first set of statuses. */ score1 = purple_buddy_presence_compute_score(buddy_presence1); /* Compute the score of the second set of statuses. */ score2 = purple_buddy_presence_compute_score(buddy_presence2); idle_time_1 = time(NULL) - purple_presence_get_idle_time(presence1); idle_time_2 = time(NULL) - purple_presence_get_idle_time(presence2); if (idle_time_1 > idle_time_2) score1 += idle_time_score; else if (idle_time_1 < idle_time_2) score2 += idle_time_score; if (score1 < score2) return 1; else if (score1 > score2) return -1; return 0; } /************************************************************************** * GObject code for PurpleAccountPresence **************************************************************************/ /* Set method for GObject properties */ static void purple_account_presence_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) { PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj); PurpleAccountPresencePrivate *priv = purple_account_presence_get_instance_private(account_presence); switch (param_id) { case ACPRES_PROP_ACCOUNT: priv->account = g_value_get_object(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } /* Get method for GObject properties */ static void purple_account_presence_get_property(GObject *obj, guint param_id, GValue *value, GParamSpec *pspec) { PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj); switch (param_id) { case ACPRES_PROP_ACCOUNT: g_value_set_object(value, purple_account_presence_get_account(account_presence)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } /* Called when done constructing */ static void purple_account_presence_constructed(GObject *object) { PurplePresence *presence = PURPLE_PRESENCE(object); PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence); PurpleAccountPresencePrivate *account_priv = purple_account_presence_get_instance_private(PURPLE_ACCOUNT_PRESENCE(presence)); G_OBJECT_CLASS(purple_account_presence_parent_class)->constructed(object); parent_priv->statuses = purple_protocol_get_statuses(account_priv->account, presence); } /* Class initializer function */ static void purple_account_presence_class_init(PurpleAccountPresenceClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_account_presence_update_idle; obj_class->constructed = purple_account_presence_constructed; /* Setup properties */ obj_class->get_property = purple_account_presence_get_property; obj_class->set_property = purple_account_presence_set_property; ap_properties[ACPRES_PROP_ACCOUNT] = g_param_spec_object("account", "Account", "The account that this presence is of.", PURPLE_TYPE_ACCOUNT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, ACPRES_PROP_LAST, ap_properties); } static void purple_account_presence_init(PurpleAccountPresence *presence) { } PurpleAccountPresence * purple_account_presence_new(PurpleAccount *account) { g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL); return g_object_new(PURPLE_TYPE_ACCOUNT_PRESENCE, "account", account, NULL); } /************************************************************************** * PurpleBuddyPresence API **************************************************************************/ static void purple_buddy_presence_update_idle(PurplePresence *presence, gboolean old_idle) { PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(presence)); GDateTime *current_time = g_date_time_new_now_utc(); PurpleAccount *account = purple_buddy_get_account(buddy); gboolean idle = purple_presence_is_idle(presence); if (!old_idle && idle) { if (purple_prefs_get_bool("/purple/logging/log_system")) { PurpleLog *log = purple_account_get_log(account, FALSE); if (log != NULL) { char *tmp, *tmp2; tmp = g_strdup_printf(_("%s became idle"), purple_buddy_get_alias(buddy)); tmp2 = g_markup_escape_text(tmp, -1); g_free(tmp); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_buddy_get_alias(buddy), current_time, tmp2); g_free(tmp2); } } } else if (old_idle && !idle) { if (purple_prefs_get_bool("/purple/logging/log_system")) { PurpleLog *log = purple_account_get_log(account, FALSE); if (log != NULL) { char *tmp, *tmp2; tmp = g_strdup_printf(_("%s became unidle"), purple_buddy_get_alias(buddy)); tmp2 = g_markup_escape_text(tmp, -1); g_free(tmp); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_buddy_get_alias(buddy), current_time, tmp2); g_free(tmp2); } } } if (old_idle != idle) purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy, old_idle, idle); purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy)); /* Should this be done here? It'd perhaps make more sense to * connect to buddy-[un]idle signals and update from there */ purple_blist_update_node(purple_blist_get_default(), PURPLE_BLIST_NODE(buddy)); g_date_time_unref(current_time); } PurpleBuddy * purple_buddy_presence_get_buddy(PurpleBuddyPresence *presence) { PurpleBuddyPresencePrivate *priv = NULL; g_return_val_if_fail(PURPLE_IS_BUDDY_PRESENCE(presence), NULL); priv = purple_buddy_presence_get_instance_private(presence); return priv->buddy; } /************************************************************************** * GObject code for PurpleBuddyPresence **************************************************************************/ /* Set method for GObject properties */ static void purple_buddy_presence_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) { PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj); PurpleBuddyPresencePrivate *priv = purple_buddy_presence_get_instance_private(buddy_presence); switch (param_id) { case BUDPRES_PROP_BUDDY: priv->buddy = g_value_get_object(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } /* Get method for GObject properties */ static void purple_buddy_presence_get_property(GObject *obj, guint param_id, GValue *value, GParamSpec *pspec) { PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj); switch (param_id) { case BUDPRES_PROP_BUDDY: g_value_set_object(value, purple_buddy_presence_get_buddy(buddy_presence)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } /* Called when done constructing */ static void purple_buddy_presence_constructed(GObject *object) { PurplePresence *presence = PURPLE_PRESENCE(object); PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence); PurpleBuddyPresencePrivate *buddy_priv = purple_buddy_presence_get_instance_private(PURPLE_BUDDY_PRESENCE(presence)); PurpleAccount *account; G_OBJECT_CLASS(purple_buddy_presence_parent_class)->constructed(object); account = purple_buddy_get_account(buddy_priv->buddy); parent_priv->statuses = purple_protocol_get_statuses(account, presence); } /* Class initializer function */ static void purple_buddy_presence_class_init(PurpleBuddyPresenceClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_buddy_presence_update_idle; obj_class->constructed = purple_buddy_presence_constructed; /* Setup properties */ obj_class->get_property = purple_buddy_presence_get_property; obj_class->set_property = purple_buddy_presence_set_property; bp_properties[BUDPRES_PROP_BUDDY] = g_param_spec_object("buddy", "Buddy", "The buddy that this presence is of.", PURPLE_TYPE_BUDDY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); g_object_class_install_properties(obj_class, BUDPRES_PROP_LAST, bp_properties); } static void purple_buddy_presence_init(PurpleBuddyPresence *presence) { } PurpleBuddyPresence * purple_buddy_presence_new(PurpleBuddy *buddy) { g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); return g_object_new(PURPLE_TYPE_BUDDY_PRESENCE, "buddy", buddy, NULL); }