Wed, 30 Aug 2017 20:33:01 -0300
facebook: Fix "Failed to read thrift" with unknown fields in /t_p payload
>Login error: Failed to read thrift: facebook-api.c:1815
>fb_api_cb_publish_pt: assertion 'FALSE' failed
/* 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 "dbus-maybe.h" #include "presence.h" #define PURPLE_PRESENCE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_PRESENCE, PurplePresencePrivate)) /** @copydoc _PurplePresencePrivate */ typedef struct _PurplePresencePrivate PurplePresencePrivate; #define PURPLE_ACCOUNT_PRESENCE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_ACCOUNT_PRESENCE, PurpleAccountPresencePrivate)) /** @copydoc _PurpleAccountPresencePrivate */ typedef struct _PurpleAccountPresencePrivate PurpleAccountPresencePrivate; #define PURPLE_BUDDY_PRESENCE_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_BUDDY_PRESENCE, PurpleBuddyPresencePrivate)) /** @copydoc _PurpleBuddyPresencePrivate */ typedef struct _PurpleBuddyPresencePrivate PurpleBuddyPresencePrivate; /** Private data for a presence */ struct _PurplePresencePrivate { gboolean idle; time_t idle_time; time_t login_time; GList *statuses; GHashTable *status_table; PurpleStatus *active_status; }; /* 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 }; /** Private data for an account presence */ struct _PurpleAccountPresencePrivate { PurpleAccount *account; }; /* Account presence property enums */ enum { ACPRES_PROP_0, ACPRES_PROP_ACCOUNT, ACPRES_PROP_LAST }; /** Private data for a buddy presence */ struct _PurpleBuddyPresencePrivate { PurpleBuddy *buddy; }; /* Buddy presence property enums */ enum { BUDPRES_PROP_0, BUDPRES_PROP_BUDDY, BUDPRES_PROP_LAST }; static GObjectClass *parent_class; static PurplePresenceClass *presence_class; static GParamSpec *properties[PRES_PROP_LAST]; static GParamSpec *ap_properties[ACPRES_PROP_LAST]; static GParamSpec *bp_properties[BUDPRES_PROP_LAST]; /************************************************************************** * 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) { gboolean old_idle; PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence); PurplePresenceClass *klass = PURPLE_PRESENCE_GET_CLASS(presence); GObject *obj; g_return_if_fail(priv != NULL); 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 = PURPLE_PRESENCE_GET_PRIVATE(presence); g_return_if_fail(priv != NULL); 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(const PurplePresence *presence) { PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence); g_return_val_if_fail(priv != NULL, NULL); return priv->statuses; } PurpleStatus * purple_presence_get_status(const PurplePresence *presence, const char *status_id) { PurpleStatus *status; PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence); GList *l = NULL; g_return_val_if_fail(priv != NULL, NULL); g_return_val_if_fail(status_id != NULL, NULL); /* 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(const PurplePresence *presence) { PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence); g_return_val_if_fail(priv != NULL, NULL); return priv->active_status; } gboolean purple_presence_is_available(const 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(const 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(const 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(const 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(const PurplePresence *presence) { PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence); g_return_val_if_fail(priv != NULL, FALSE); return purple_presence_is_online(presence) && priv->idle; } time_t purple_presence_get_idle_time(const PurplePresence *presence) { PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence); g_return_val_if_fail(priv != NULL, 0); return priv->idle_time; } time_t purple_presence_get_login_time(const PurplePresence *presence) { PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence); g_return_val_if_fail(priv != NULL, 0); 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_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(GTypeInstance *instance, gpointer klass) { PURPLE_DBUS_REGISTER_POINTER(PURPLE_PRESENCE(instance), PurplePresence); PURPLE_PRESENCE_GET_PRIVATE(instance)->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_PRIVATE(object); if (priv->statuses) { g_list_foreach(priv->statuses, (GFunc)g_object_unref, NULL); g_list_free(priv->statuses); priv->statuses = NULL; } parent_class->dispose(object); } /* GObject finalize function */ static void purple_presence_finalize(GObject *object) { PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(object); g_hash_table_destroy(priv->status_table); PURPLE_DBUS_UNREGISTER_POINTER(object); parent_class->finalize(object); } /* Class initializer function */ static void purple_presence_class_init(PurplePresenceClass *klass) { GObjectClass *obj_class = G_OBJECT_CLASS(klass); parent_class = g_type_class_peek_parent(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; g_type_class_add_private(klass, sizeof(PurplePresencePrivate)); 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); } GType purple_presence_get_type(void) { static GType type = 0; if(type == 0) { static const GTypeInfo info = { sizeof(PurplePresenceClass), NULL, NULL, (GClassInitFunc)purple_presence_class_init, NULL, NULL, sizeof(PurplePresence), 0, (GInstanceInitFunc)purple_presence_init, NULL, }; type = g_type_register_static(G_TYPE_OBJECT, "PurplePresence", &info, G_TYPE_FLAG_ABSTRACT); } return type; } /************************************************************************** * 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(const PurpleAccountPresence *presence) { PurpleAccountPresencePrivate *priv = PURPLE_ACCOUNT_PRESENCE_GET_PRIVATE(presence); g_return_val_if_fail(priv != NULL, NULL); return priv->account; } static int purple_buddy_presence_compute_score(const 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(const PurpleBuddyPresence *buddy_presence1, const 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_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); PurpleAccountPresencePrivate *priv = PURPLE_ACCOUNT_PRESENCE_GET_PRIVATE(presence); G_OBJECT_CLASS(presence_class)->constructed(object); PURPLE_PRESENCE_GET_PRIVATE(presence)->statuses = purple_protocol_get_statuses(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; presence_class = g_type_class_peek_parent(klass); 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; g_type_class_add_private(klass, sizeof(PurpleAccountPresencePrivate)); 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); } GType purple_account_presence_get_type(void) { static GType type = 0; if(type == 0) { static const GTypeInfo info = { sizeof(PurpleAccountPresenceClass), NULL, NULL, (GClassInitFunc)purple_account_presence_class_init, NULL, NULL, sizeof(PurpleAccountPresence), 0, NULL, NULL, }; type = g_type_register_static(PURPLE_TYPE_PRESENCE, "PurpleAccountPresence", &info, 0); } return type; } 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(); PurpleBlistUiOps *ops = purple_blist_get_ui_ops(); 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 */ if (ops != NULL && ops->update != NULL) ops->update(purple_blist_get_buddy_list(), (PurpleBlistNode *)buddy); g_date_time_unref(current_time); } PurpleBuddy * purple_buddy_presence_get_buddy(const PurpleBuddyPresence *presence) { PurpleBuddyPresencePrivate *priv = PURPLE_BUDDY_PRESENCE_GET_PRIVATE(presence); g_return_val_if_fail(priv != NULL, NULL); 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_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); PurpleBuddyPresencePrivate *priv = PURPLE_BUDDY_PRESENCE_GET_PRIVATE(presence); PurpleAccount *account; G_OBJECT_CLASS(presence_class)->constructed(object); account = purple_buddy_get_account(priv->buddy); PURPLE_PRESENCE_GET_PRIVATE(presence)->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; presence_class = g_type_class_peek_parent(klass); 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; g_type_class_add_private(klass, sizeof(PurpleBuddyPresencePrivate)); 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); } GType purple_buddy_presence_get_type(void) { static GType type = 0; if(type == 0) { static const GTypeInfo info = { sizeof(PurpleBuddyPresenceClass), NULL, NULL, (GClassInitFunc)purple_buddy_presence_class_init, NULL, NULL, sizeof(PurpleBuddyPresence), 0, NULL, NULL, }; type = g_type_register_static(PURPLE_TYPE_PRESENCE, "PurpleBuddyPresence", &info, 0); } return type; } 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); }