* 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, see <https://www.gnu.org/licenses/>.
#include <glib/gi18n-lib.h>
#include "purplebuddypresence.h"
#include "purpleprivate.h"
struct _PurpleBuddyPresence {
static GParamSpec *properties[N_PROPERTIES];
/******************************************************************************
*****************************************************************************/
purple_buddy_presence_set_buddy(PurpleBuddyPresence *presence,
if(g_set_object(&presence->buddy, buddy)) {
g_object_notify_by_pspec(G_OBJECT(presence), properties[PROP_BUDDY]);
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)
/******************************************************************************
* PurplePresence Implementation
*****************************************************************************/
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_statuses(PurplePresence *presence) {
PurpleAccount *account = NULL;
PurpleBuddyPresence *buddy_presence = NULL;
buddy_presence = PURPLE_BUDDY_PRESENCE(presence);
account = purple_buddy_get_account(buddy_presence->buddy);
return purple_protocol_get_statuses(account, presence);
/******************************************************************************
*****************************************************************************/
G_DEFINE_TYPE(PurpleBuddyPresence, purple_buddy_presence, PURPLE_TYPE_PRESENCE)
purple_buddy_presence_set_property(GObject *obj, guint param_id,
const GValue *value, GParamSpec *pspec)
PurpleBuddyPresence *presence = PURPLE_BUDDY_PRESENCE(obj);
purple_buddy_presence_set_buddy(presence,
g_value_get_object(value));
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
purple_buddy_presence_get_property(GObject *obj, guint param_id, GValue *value,
PurpleBuddyPresence *presence = PURPLE_BUDDY_PRESENCE(obj);
g_value_set_object(value,
purple_buddy_presence_get_buddy(presence));
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
purple_buddy_presence_finalize(GObject *obj) {
PurpleBuddyPresence *presence = PURPLE_BUDDY_PRESENCE(obj);
g_clear_object(&presence->buddy);
G_OBJECT_CLASS(purple_buddy_presence_parent_class)->finalize(obj);
purple_buddy_presence_init(PurpleBuddyPresence *presence) {
purple_buddy_presence_class_init(PurpleBuddyPresenceClass *klass) {
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
PurplePresenceClass *presence_class = PURPLE_PRESENCE_CLASS(klass);
obj_class->get_property = purple_buddy_presence_get_property;
obj_class->set_property = purple_buddy_presence_set_property;
obj_class->finalize = purple_buddy_presence_finalize;
presence_class->update_idle = purple_buddy_presence_update_idle;
presence_class->get_statuses = purple_buddy_presence_get_statuses;
properties[PROP_BUDDY] = g_param_spec_object(
"The buddy for this presence.",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
/******************************************************************************
*****************************************************************************/
purple_buddy_presence_new(PurpleBuddy *buddy) {
g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
PURPLE_TYPE_BUDDY_PRESENCE,
purple_buddy_presence_get_buddy(PurpleBuddyPresence *presence) {
g_return_val_if_fail(PURPLE_IS_BUDDY_PRESENCE(presence), NULL);