* 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 /************************************************************************** **************************************************************************/ /** Private data for a presence */ GHashTable *status_table; PurpleStatus *active_status; /* Presence property enums */ static GParamSpec *properties[PRES_PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurplePresence, purple_presence, G_TYPE_OBJECT) /************************************************************************** **************************************************************************/ * A presence for an account struct _PurpleAccountPresence /** Private data for an account presence */ } PurpleAccountPresencePrivate; /* Account presence property enums */ static GParamSpec *ap_properties[ACPRES_PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurpleAccountPresence, purple_account_presence, /************************************************************************** **************************************************************************/ struct _PurpleBuddyPresence /** Private data for a buddy presence */ } PurpleBuddyPresencePrivate; /* Buddy presence property enums */ static GParamSpec *bp_properties[BUDPRES_PROP_LAST]; G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddyPresence, purple_buddy_presence, /************************************************************************** **************************************************************************/ purple_presence_set_status_active(PurplePresence *presence, const char *status_id, 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)) purple_debug_warning("presence", "Attempted to set a non-independent status " "(%s) inactive. Only independent statuses " "can be specifically marked inactive.", purple_status_set_active(status, active); purple_presence_switch_status(PurplePresence *presence, const char *status_id) purple_presence_set_status_active(presence, status_id, TRUE); purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time) PurplePresencePrivate *priv = NULL; PurplePresenceClass *klass = NULL; 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) 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); klass->update_idle(presence, old_idle); 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) priv->login_time = login_time; g_object_notify_by_pspec(G_OBJECT(presence), properties[PRES_PROP_LOGIN_TIME]); 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); purple_presence_get_status(PurplePresence *presence, const char *status_id) PurplePresencePrivate *priv = 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, 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))) g_hash_table_insert(priv->status_table, g_strdup(purple_status_get_id(status)), status); 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; purple_presence_is_available(PurplePresence *presence) 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)); purple_presence_is_online(PurplePresence *presence) g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE); if ((status = purple_presence_get_active_status(presence)) == NULL) return purple_status_is_online(status); purple_presence_is_status_active(PurplePresence *presence, 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)); purple_presence_is_status_primitive_active(PurplePresence *presence, PurpleStatusPrimitive primitive) 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); 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)) 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; 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); 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 */ purple_presence_set_property(GObject *obj, guint param_id, const GValue *value, PurplePresence *presence = PURPLE_PRESENCE(obj); PurplePresencePrivate *priv = purple_presence_get_instance_private(presence); purple_presence_set_idle(presence, g_value_get_boolean(value), 0); case PRES_PROP_IDLE_TIME: purple_presence_set_idle(presence, TRUE, g_value_get_int(value)); purple_presence_set_idle(presence, TRUE, g_value_get_int64(value)); #error Unknown size of time_t case PRES_PROP_LOGIN_TIME: purple_presence_set_login_time(presence, g_value_get_int(value)); purple_presence_set_login_time(presence, g_value_get_int64(value)); #error Unknown size of time_t case PRES_PROP_ACTIVE_STATUS: priv->active_status = g_value_get_object(value); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* Get method for GObject properties */ purple_presence_get_property(GObject *obj, guint param_id, GValue *value, PurplePresence *presence = PURPLE_PRESENCE(obj); g_value_set_boolean(value, purple_presence_is_idle(presence)); case PRES_PROP_IDLE_TIME: g_value_set_int(value, purple_presence_get_idle_time(presence)); g_value_set_int64(value, purple_presence_get_idle_time(presence)); #error Unknown size of time_t case PRES_PROP_LOGIN_TIME: g_value_set_int(value, purple_presence_get_login_time(presence)); g_value_set_int64(value, purple_presence_get_login_time(presence)); #error Unknown size of time_t g_value_set_pointer(value, purple_presence_get_statuses(presence)); case PRES_PROP_ACTIVE_STATUS: g_value_set_object(value, purple_presence_get_active_status(presence)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* GObject initialization function */ 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 */ purple_presence_dispose(GObject *object) PurplePresencePrivate *priv = purple_presence_get_instance_private(PURPLE_PRESENCE(object)); g_list_free_full(priv->statuses, (GDestroyNotify)g_object_unref); G_OBJECT_CLASS(purple_presence_parent_class)->dispose(object); /* GObject finalize function */ 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; 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] = #error Unknown size of time_t ("idle-time", "Idle time", "The idle time of the presence", G_MININT64, G_MAXINT64, 0, #error Unknown size of time_t G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PRES_PROP_LOGIN_TIME] = #error Unknown size of time_t ("login-time", "Login time", "The login time of the presence.", G_MININT64, G_MAXINT64, 0, #error Unknown size of time_t G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); properties[PRES_PROP_STATUSES] = g_param_spec_pointer("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", "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 **************************************************************************/ purple_account_presence_update_idle(PurplePresence *presence, gboolean old_idle) 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); tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account)); dt = g_date_time_new_from_unix_local(idle_time); 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); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_account_get_username(account), gc = purple_account_get_connection(account); if(PURPLE_CONNECTION_IS_CONNECTED(gc)) protocol = purple_connection_get_protocol(gc); purple_protocol_server_iface_set_idle(protocol, gc, (idle ? (current_time - idle_time) : 0)); 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); purple_buddy_presence_compute_score(PurpleBuddyPresence *buddy_presence) 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 += purple_account_get_int(purple_buddy_get_account(b), "score", 0); if (purple_presence_is_idle(presence)) 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) else if (presence1 == NULL) else if (presence2 == NULL) if (purple_presence_is_online(presence1) && !purple_presence_is_online(presence2)) else if (purple_presence_is_online(presence2) && !purple_presence_is_online(presence1)) /* 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; else if (score1 > score2) /************************************************************************** * GObject code for PurpleAccountPresence **************************************************************************/ /* Set method for GObject properties */ purple_account_presence_set_property(GObject *obj, guint param_id, const GValue *value, PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj); PurpleAccountPresencePrivate *priv = purple_account_presence_get_instance_private(account_presence); case ACPRES_PROP_ACCOUNT: priv->account = g_value_get_object(value); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* Get method for GObject properties */ purple_account_presence_get_property(GObject *obj, guint param_id, GValue *value, PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj); case ACPRES_PROP_ACCOUNT: g_value_set_object(value, purple_account_presence_get_account(account_presence)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* Called when done constructing */ 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; 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", "The account that this presence is of.", PURPLE_TYPE_ACCOUNT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | g_object_class_install_properties(obj_class, ACPRES_PROP_LAST, purple_account_presence_init(PurpleAccountPresence *presence) purple_account_presence_new(PurpleAccount *account) g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL); return g_object_new(PURPLE_TYPE_ACCOUNT_PRESENCE, /************************************************************************** * PurpleBuddyPresence API **************************************************************************/ 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 (purple_prefs_get_bool("/purple/logging/log_system")) PurpleLog *log = purple_account_get_log(account, FALSE); tmp = g_strdup_printf(_("%s became idle"), purple_buddy_get_alias(buddy)); tmp2 = g_markup_escape_text(tmp, -1); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_buddy_get_alias(buddy), else if (old_idle && !idle) if (purple_prefs_get_bool("/purple/logging/log_system")) PurpleLog *log = purple_account_get_log(account, FALSE); tmp = g_strdup_printf(_("%s became unidle"), purple_buddy_get_alias(buddy)); tmp2 = g_markup_escape_text(tmp, -1); purple_log_write(log, PURPLE_MESSAGE_SYSTEM, purple_buddy_get_alias(buddy), purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy, 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); 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); /************************************************************************** * GObject code for PurpleBuddyPresence **************************************************************************/ /* Set method for GObject properties */ purple_buddy_presence_set_property(GObject *obj, guint param_id, const GValue *value, PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj); PurpleBuddyPresencePrivate *priv = purple_buddy_presence_get_instance_private(buddy_presence); priv->buddy = g_value_get_object(value); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* Get method for GObject properties */ purple_buddy_presence_get_property(GObject *obj, guint param_id, GValue *value, PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj); g_value_set_object(value, purple_buddy_presence_get_buddy(buddy_presence)); G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); /* Called when done constructing */ 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)); 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; 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_object_class_install_properties(obj_class, BUDPRES_PROP_LAST, purple_buddy_presence_init(PurpleBuddyPresence *presence) purple_buddy_presence_new(PurpleBuddy *buddy) g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL); return g_object_new(PURPLE_TYPE_BUDDY_PRESENCE,