* 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
#include <glib/gi18n-lib.h>
#include "purpleprivate.h"
#include "purpleaccountpresence.h"
#include "purplebuddypresence.h"
typedef struct _PurpleStatusPrivate PurpleStatusPrivate;
PurpleStatusPrimitive primitive;
struct _PurpleStatusAttribute
* A PurpleStatus can be thought of as an "instance" of a PurpleStatusType.
* If you're familiar with object-oriented programming languages
* then this should be immediately clear. Say, for example, that
* one of your AIM buddies has set himself as "away." You have a
* PurpleBuddy node for this person in your buddy list. Purple wants
* to mark this buddy as "away," so it creates a new PurpleStatus.
* The PurpleStatus has its PurpleStatusType set to the "away" state
* for the oscar protocol. The PurpleStatus also contains the buddy's
* away message. PurpleStatuses are sometimes saved, depending on
* the context. The current PurpleStatuses associated with each of
* your accounts are saved so that the next time you start Purple,
* your accounts will be set to their last known statuses. There
* is also a list of saved statuses that are written to the
* status.xml file. Also, each PurpleStatus has a "saveable" boolean.
* If "saveable" is set to FALSE then the status is NEVER saved.
* All PurpleStatuses should be inside a PurplePresence.
* A PurpleStatus is either "independent" or "exclusive."
* Independent statuses can be active or inactive and they don't
* affect anything else. However, you can only have one exclusive
* status per PurplePresence. If you activate one exclusive status,
* then the previous exclusive status is automatically deactivated.
* A PurplePresence is like a collection of PurpleStatuses (plus some
* See <link linkend="libpurple-presence">Presence API</link>
* Private data for PurpleStatus
struct _PurpleStatusPrivate
PurpleStatusType *status_type;
PurplePresence *presence;
* The current values of the attributes for this status. The
* key is a string containing the name of the attribute. It is
* a borrowed reference from the list of attrs in the
* PurpleStatusType. The value is a GValue.
/* GObject property enums */
static GParamSpec *properties[PROP_LAST];
G_DEFINE_TYPE_WITH_PRIVATE(PurpleStatus, purple_status, G_TYPE_OBJECT);
static int primitive_scores[] =
-200, /* extended away */
-10, /* idle, special case. */
-5, /* idle time, special case. */
10 /* Offline messageable */
#define SCORE_IDLE_TIME 10
#define SCORE_OFFLINE_MESSAGE 11
/**************************************************************************
* PurpleStatusPrimitive API
**************************************************************************/
static struct PurpleStatusPrimitiveMap
PurpleStatusPrimitive type;
} const status_primitive_map[] =
{ PURPLE_STATUS_UNSET, "unset", N_("Unset") },
{ PURPLE_STATUS_OFFLINE, "offline", N_("Offline") },
{ PURPLE_STATUS_AVAILABLE, "available", N_("Available") },
{ PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") },
{ PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") },
{ PURPLE_STATUS_AWAY, "away", N_("Away") },
{ PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") },
{ PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") },
{ PURPLE_STATUS_TUNE, "tune", N_("Listening to music"), },
{ PURPLE_STATUS_MOOD, "mood", N_("Feeling") },
_purple_statuses_get_primitive_scores(void)
purple_primitive_get_id_from_type(PurpleStatusPrimitive type)
for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
if (type == status_primitive_map[i].type)
return status_primitive_map[i].id;
return status_primitive_map[0].id;
purple_primitive_get_name_from_type(PurpleStatusPrimitive type)
for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
if (type == status_primitive_map[i].type)
return _(status_primitive_map[i].name);
return _(status_primitive_map[0].name);
purple_primitive_get_type_from_id(const char *id)
g_return_val_if_fail(id != NULL, PURPLE_STATUS_UNSET);
for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
if (purple_strequal(id, status_primitive_map[i].id))
return status_primitive_map[i].type;
return status_primitive_map[0].type;
/**************************************************************************
**************************************************************************/
purple_status_type_new_full(PurpleStatusPrimitive primitive, const char *id,
const char *name, gboolean saveable,
gboolean user_settable, gboolean independent)
PurpleStatusType *status_type;
g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
status_type = g_new0(PurpleStatusType, 1);
status_type->primitive = primitive;
status_type->saveable = saveable;
status_type->user_settable = user_settable;
status_type->independent = independent;
status_type->id = g_strdup(id);
status_type->id = g_strdup(purple_primitive_get_id_from_type(primitive));
status_type->name = g_strdup(name);
status_type->name = g_strdup(purple_primitive_get_name_from_type(primitive));
purple_status_type_new(PurpleStatusPrimitive primitive, const char *id,
const char *name, gboolean user_settable)
g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
return purple_status_type_new_full(primitive, id, name, TRUE,
status_type_add_attr(PurpleStatusType *status_type, const char *id,
const char *name, GValue *value)
PurpleStatusAttribute *attr;
g_return_if_fail(status_type != NULL);
g_return_if_fail(id != NULL);
g_return_if_fail(name != NULL);
g_return_if_fail(value != NULL);
attr = purple_status_attribute_new(id, name, value);
status_type->attrs = g_list_append(status_type->attrs, attr);
status_type_add_attrs_vargs(PurpleStatusType *status_type, va_list args)
g_return_if_fail(status_type != NULL);
while ((id = va_arg(args, const char *)) != NULL)
name = va_arg(args, const char *);
g_return_if_fail(name != NULL);
value = va_arg(args, GValue *);
g_return_if_fail(value != NULL);
status_type_add_attr(status_type, id, name, value);
purple_status_type_new_with_attrs(PurpleStatusPrimitive primitive,
const char *id, const char *name,
gboolean saveable, gboolean user_settable,
gboolean independent, const char *attr_id,
const char *attr_name, GValue *attr_value,
PurpleStatusType *status_type;
g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
g_return_val_if_fail(attr_id != NULL, NULL);
g_return_val_if_fail(attr_name != NULL, NULL);
g_return_val_if_fail(attr_value != NULL, NULL);
status_type = purple_status_type_new_full(primitive, id, name, saveable,
user_settable, independent);
/* Add the first attribute */
status_type_add_attr(status_type, attr_id, attr_name, attr_value);
va_start(args, attr_value);
status_type_add_attrs_vargs(status_type, args);
purple_status_type_destroy(PurpleStatusType *status_type)
g_return_if_fail(status_type != NULL);
g_free(status_type->name);
g_list_free_full(status_type->attrs,
(GDestroyNotify)purple_status_attribute_destroy);
purple_status_type_get_primitive(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, PURPLE_STATUS_UNSET);
return status_type->primitive;
purple_status_type_get_id(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, NULL);
purple_status_type_get_name(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, NULL);
return status_type->name;
purple_status_type_is_saveable(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, FALSE);
return status_type->saveable;
purple_status_type_is_user_settable(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, FALSE);
return status_type->user_settable;
purple_status_type_is_independent(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, FALSE);
return status_type->independent;
purple_status_type_is_exclusive(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, FALSE);
return !status_type->independent;
purple_status_type_is_available(const PurpleStatusType *status_type)
PurpleStatusPrimitive primitive;
g_return_val_if_fail(status_type != NULL, FALSE);
primitive = purple_status_type_get_primitive(status_type);
return (primitive == PURPLE_STATUS_AVAILABLE);
purple_status_type_get_attr(const PurpleStatusType *status_type, const char *id)
g_return_val_if_fail(status_type != NULL, NULL);
g_return_val_if_fail(id != NULL, NULL);
for (l = status_type->attrs; l != NULL; l = l->next)
PurpleStatusAttribute *attr = (PurpleStatusAttribute *)l->data;
if (purple_strequal(purple_status_attribute_get_id(attr), id))
purple_status_type_get_attrs(const PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, NULL);
return status_type->attrs;
purple_status_type_find_with_id(GList *status_types, const char *id)
PurpleStatusType *status_type;
g_return_val_if_fail(id != NULL, NULL);
while (status_types != NULL)
status_type = status_types->data;
if (purple_strequal(id, status_type->id))
status_types = status_types->next;
/**************************************************************************
* PurpleStatusAttribute API
**************************************************************************/
purple_status_attribute_new(const char *id, const char *name, GValue *value_type)
PurpleStatusAttribute *attr;
g_return_val_if_fail(id != NULL, NULL);
g_return_val_if_fail(name != NULL, NULL);
g_return_val_if_fail(value_type != NULL, NULL);
attr = g_new0(PurpleStatusAttribute, 1);
attr->name = g_strdup(name);
attr->value_type = value_type;
purple_status_attribute_destroy(PurpleStatusAttribute *attr)
g_return_if_fail(attr != NULL);
purple_value_free(attr->value_type);
purple_status_attribute_get_id(const PurpleStatusAttribute *attr)
g_return_val_if_fail(attr != NULL, NULL);
purple_status_attribute_get_name(const PurpleStatusAttribute *attr)
g_return_val_if_fail(attr != NULL, NULL);
purple_status_attribute_get_value(const PurpleStatusAttribute *attr)
g_return_val_if_fail(attr != NULL, NULL);
/**************************************************************************
**************************************************************************/
notify_buddy_status_update(PurpleBuddy *buddy, PurplePresence *presence,
PurpleStatus *old_status, PurpleStatus *new_status)
if (purple_prefs_get_bool("/purple/logging/log_system"))
GDateTime *current_time = g_date_time_new_now_utc();
const char *buddy_alias = purple_buddy_get_alias(buddy);
tmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias,
purple_buddy_get_name(buddy),
purple_status_get_name(old_status),
purple_status_get_name(new_status));
logtmp = g_markup_escape_text(tmp, -1);
/* old_status == NULL when an independent status is toggled. */
if (purple_status_is_active(new_status))
tmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias,
purple_buddy_get_name(buddy),
purple_status_get_name(new_status));
logtmp = g_markup_escape_text(tmp, -1);
tmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias,
purple_buddy_get_name(buddy),
purple_status_get_name(new_status));
logtmp = g_markup_escape_text(tmp, -1);
log = purple_account_get_log(purple_buddy_get_account(buddy), FALSE);
purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
g_date_time_unref(current_time);
notify_status_update(PurplePresence *presence, PurpleStatus *old_status,
PurpleStatus *new_status)
if (PURPLE_IS_ACCOUNT_PRESENCE(presence))
PurpleAccount *account = purple_account_presence_get_account(
PURPLE_ACCOUNT_PRESENCE(presence));
PurpleAccountUiOps *ops = purple_accounts_get_ui_ops();
if (purple_account_get_enabled(account, purple_core_get_ui()))
purple_protocol_change_account_status(account, old_status, new_status);
if (ops != NULL && ops->status_changed != NULL)
ops->status_changed(account, new_status);
else if (PURPLE_IS_BUDDY_PRESENCE(presence))
notify_buddy_status_update(purple_buddy_presence_get_buddy(
PURPLE_BUDDY_PRESENCE(presence)), presence, old_status,
status_has_changed(PurpleStatus *status)
PurplePresence *presence;
PurpleStatus *old_status;
presence = purple_status_get_presence(status);
* If this status is exclusive, then we must be setting it to "active."
* Since we are setting it to active, we want to set the currently
* active status to "inactive."
if (purple_status_is_exclusive(status))
old_status = purple_presence_get_active_status(presence);
if (old_status != NULL && (old_status != status)) {
PurpleStatusPrivate *priv = purple_status_get_instance_private(old_status);
g_object_notify_by_pspec(G_OBJECT(old_status),
properties[PROP_ACTIVE]);
g_object_set(presence, "active-status", status, NULL);
g_object_notify_by_pspec(G_OBJECT(status), properties[PROP_ACTIVE]);
notify_status_update(presence, old_status, status);
status_set_attr_boolean(PurpleStatus *status, const char *id,
g_return_if_fail(PURPLE_IS_STATUS(status));
g_return_if_fail(id != NULL);
/* Make sure this attribute exists and is the correct type. */
attr_value = purple_status_get_attr_value(status, id);
g_return_if_fail(attr_value != NULL);
g_return_if_fail(G_VALUE_TYPE(attr_value) == G_TYPE_BOOLEAN);
g_value_set_boolean(attr_value, value);
status_set_attr_int(PurpleStatus *status, const char *id, int value)
g_return_if_fail(PURPLE_IS_STATUS(status));
g_return_if_fail(id != NULL);
/* Make sure this attribute exists and is the correct type. */
attr_value = purple_status_get_attr_value(status, id);
g_return_if_fail(attr_value != NULL);
g_return_if_fail(G_VALUE_TYPE(attr_value) == G_TYPE_INT);
g_value_set_int(attr_value, value);
status_set_attr_string(PurpleStatus *status, const char *id,
g_return_if_fail(PURPLE_IS_STATUS(status));
g_return_if_fail(id != NULL);
/* Make sure this attribute exists and is the correct type. */
attr_value = purple_status_get_attr_value(status, id);
/* This used to be g_return_if_fail, but it's failing a LOT, so
* let's generate a log error for now. */
/* g_return_if_fail(attr_value != NULL); */
if (attr_value == NULL) {
purple_debug_error("status",
"Attempted to set status attribute '%s' for "
"status '%s', which is not legal. Fix "
purple_status_type_get_name(purple_status_get_status_type(status)));
g_return_if_fail(G_VALUE_TYPE(attr_value) == G_TYPE_STRING);
/* XXX: Check if the value has actually changed. If it has, and the status
* is active, should this trigger 'status_has_changed'? */
g_value_set_string(attr_value, value);
purple_status_set_active(PurpleStatus *status, gboolean active)
purple_status_set_active_with_attrs_dict(status, active, NULL);
* This used to parse the va_list directly, but now it creates a GList
* and passes it to purple_status_set_active_with_attrs_list(). That
* function was created because account.c needs to pass a GList of
* attributes to the status API.
purple_status_set_active_with_attrs(PurpleStatus *status, gboolean active, va_list args)
GHashTable *attrs = purple_attrs_from_vargs(args);
purple_status_set_active_with_attrs_dict(status, active, attrs);
g_hash_table_destroy(attrs);
purple_status_set_active_with_attrs_dict(PurpleStatus *status, gboolean active,
PurpleStatusPrivate *priv = NULL;
gboolean changed = FALSE;
GList *specified_attr_ids = NULL;
PurpleStatusType *status_type;
g_return_if_fail(PURPLE_IS_STATUS(status));
g_return_if_fail(attrs != NULL);
priv = purple_status_get_instance_private(status);
if (!active && purple_status_is_exclusive(status))
purple_debug_error("status",
"Cannot deactivate an exclusive status (%s).\n",
purple_status_get_id(status));
if (priv->active != active)
g_hash_table_iter_init(&iter, attrs);
while (g_hash_table_iter_next(&iter, (gpointer *)&id, (gpointer *)&data)) {
value = purple_status_get_attr_value(status, id);
purple_debug_warning("status", "The attribute \"%s\" on the status \"%s\" is "
"not supported.\n", id, priv->status_type->name);
/* Skip over the data and move on to the next attribute */
specified_attr_ids = g_list_prepend(specified_attr_ids, (gpointer)id);
if (G_VALUE_TYPE(value) == G_TYPE_STRING)
const gchar *string_data = data;
if (purple_strequal(string_data, g_value_get_string(value)))
status_set_attr_string(status, id, string_data);
else if (G_VALUE_TYPE(value) == G_TYPE_INT)
int int_data = GPOINTER_TO_INT(data);
if (int_data == g_value_get_int(value))
status_set_attr_int(status, id, int_data);
else if (G_VALUE_TYPE(value) == G_TYPE_BOOLEAN)
gboolean boolean_data = GPOINTER_TO_INT(data);
if (boolean_data == g_value_get_boolean(value))
status_set_attr_boolean(status, id, boolean_data);
/* Reset any unspecified attributes to their default value */
status_type = purple_status_get_status_type(status);
l = purple_status_type_get_attrs(status_type);
PurpleStatusAttribute *attr;
if (!g_list_find_custom(specified_attr_ids, attr->id, (GCompareFunc)strcmp)) {
default_value = purple_status_attribute_get_value(attr);
if (G_VALUE_TYPE(default_value) == G_TYPE_STRING) {
const char *cur = purple_status_get_attr_string(status, attr->id);
const char *def = g_value_get_string(default_value);
if (purple_strequal(cur, def)) {
status_set_attr_string(status, attr->id, def);
} else if (G_VALUE_TYPE(default_value) == G_TYPE_INT) {
int cur = purple_status_get_attr_int(status, attr->id);
int def = g_value_get_int(default_value);
status_set_attr_int(status, attr->id, def);
} else if (G_VALUE_TYPE(default_value) == G_TYPE_BOOLEAN) {
gboolean cur = purple_status_get_attr_boolean(status, attr->id);
gboolean def = g_value_get_boolean(default_value);
status_set_attr_boolean(status, attr->id, def);
g_list_free(specified_attr_ids);
status_has_changed(status);
purple_status_get_status_type(PurpleStatus *status)
PurpleStatusPrivate *priv = NULL;
g_return_val_if_fail(PURPLE_IS_STATUS(status), NULL);
priv = purple_status_get_instance_private(status);
return priv->status_type;
purple_status_get_presence(PurpleStatus *status)
PurpleStatusPrivate *priv = NULL;
g_return_val_if_fail(PURPLE_IS_STATUS(status), NULL);
priv = purple_status_get_instance_private(status);
purple_status_get_id(PurpleStatus *status)
g_return_val_if_fail(PURPLE_IS_STATUS(status), NULL);
return purple_status_type_get_id(purple_status_get_status_type(status));
purple_status_get_name(PurpleStatus *status)
g_return_val_if_fail(PURPLE_IS_STATUS(status), NULL);
return purple_status_type_get_name(purple_status_get_status_type(status));
purple_status_is_independent(PurpleStatus *status)
g_return_val_if_fail(PURPLE_IS_STATUS(status), FALSE);
return purple_status_type_is_independent(purple_status_get_status_type(status));
purple_status_is_exclusive(PurpleStatus *status)
g_return_val_if_fail(PURPLE_IS_STATUS(status), FALSE);
return purple_status_type_is_exclusive(purple_status_get_status_type(status));
purple_status_is_available(PurpleStatus *status)
g_return_val_if_fail(PURPLE_IS_STATUS(status), FALSE);
return purple_status_type_is_available(purple_status_get_status_type(status));
purple_status_is_active(PurpleStatus *status)
PurpleStatusPrivate *priv = NULL;
g_return_val_if_fail(PURPLE_IS_STATUS(status), FALSE);
priv = purple_status_get_instance_private(status);
purple_status_is_online(PurpleStatus *status)
PurpleStatusPrimitive primitive;
g_return_val_if_fail(PURPLE_IS_STATUS(status), FALSE);
primitive = purple_status_type_get_primitive(purple_status_get_status_type(status));
return (primitive != PURPLE_STATUS_UNSET &&
primitive != PURPLE_STATUS_OFFLINE);
purple_status_get_attr_value(PurpleStatus *status, const char *id)
PurpleStatusPrivate *priv = NULL;
g_return_val_if_fail(PURPLE_IS_STATUS(status), NULL);
g_return_val_if_fail(id != NULL, NULL);
priv = purple_status_get_instance_private(status);
return (GValue *)g_hash_table_lookup(priv->attr_values, id);
purple_status_get_attr_boolean(PurpleStatus *status, const char *id)
g_return_val_if_fail(PURPLE_IS_STATUS(status), FALSE);
g_return_val_if_fail(id != NULL, FALSE);
if ((value = purple_status_get_attr_value(status, id)) == NULL)
g_return_val_if_fail(G_VALUE_TYPE(value) == G_TYPE_BOOLEAN, FALSE);
return g_value_get_boolean(value);
purple_status_get_attr_int(PurpleStatus *status, const char *id)
g_return_val_if_fail(PURPLE_IS_STATUS(status), 0);
g_return_val_if_fail(id != NULL, 0);
if ((value = purple_status_get_attr_value(status, id)) == NULL)
g_return_val_if_fail(G_VALUE_TYPE(value) == G_TYPE_INT, 0);
return g_value_get_int(value);
purple_status_get_attr_string(PurpleStatus *status, const char *id)
g_return_val_if_fail(PURPLE_IS_STATUS(status), NULL);
g_return_val_if_fail(id != NULL, NULL);
if ((value = purple_status_get_attr_value(status, id)) == NULL)
g_return_val_if_fail(G_VALUE_TYPE(value) == G_TYPE_STRING, NULL);
return g_value_get_string(value);
purple_status_compare(PurpleStatus *status1, PurpleStatus *status2)
PurpleStatusType *type1, *type2;
int score1 = 0, score2 = 0;
if ((status1 == NULL && status2 == NULL) ||
else if (status1 == NULL)
else if (status2 == NULL)
type1 = purple_status_get_status_type(status1);
type2 = purple_status_get_status_type(status2);
if (purple_status_is_active(status1))
score1 = primitive_scores[purple_status_type_get_primitive(type1)];
if (purple_status_is_active(status2))
score2 = primitive_scores[purple_status_type_get_primitive(type2)];
else if (score1 < score2)
/**************************************************************************
* GBoxed code for PurpleStatusType
**************************************************************************/
static PurpleStatusType *
purple_status_type_ref(PurpleStatusType *status_type)
g_return_val_if_fail(status_type != NULL, NULL);
status_type->box_count++;
purple_status_type_unref(PurpleStatusType *status_type)
g_return_if_fail(status_type != NULL);
g_return_if_fail(status_type->box_count >= 0);
if (!status_type->box_count--)
purple_status_type_destroy(status_type);
purple_status_type_get_type(void)
type = g_boxed_type_register_static("PurpleStatusType",
(GBoxedCopyFunc)purple_status_type_ref,
(GBoxedFreeFunc)purple_status_type_unref);
/**************************************************************************
* GBoxed code for PurpleStatusAttribute
**************************************************************************/
static PurpleStatusAttribute *
purple_status_attribute_copy(PurpleStatusAttribute *status_attr)
g_return_val_if_fail(status_attr != NULL, NULL);
return purple_status_attribute_new(status_attr->id,
purple_value_dup(status_attr->value_type));
purple_status_attribute_get_type(void)
type = g_boxed_type_register_static("PurpleStatusAttribute",
(GBoxedCopyFunc)purple_status_attribute_copy,
(GBoxedFreeFunc)purple_status_attribute_destroy);
/**************************************************************************
* GBoxed code for PurpleMood
**************************************************************************/
purple_mood_copy(PurpleMood *mood)
g_return_val_if_fail(mood != NULL, NULL);
mood_copy = g_new(PurpleMood, 1);
mood_copy->mood = g_strdup(mood->mood);
mood_copy->description = g_strdup(mood->description);
purple_mood_free(PurpleMood *mood)
g_free((gchar *)mood->mood);
g_free((gchar *)mood->description);
purple_mood_get_type(void)
type = g_boxed_type_register_static("PurpleMood",
(GBoxedCopyFunc)purple_mood_copy,
(GBoxedFreeFunc)purple_mood_free);
/**************************************************************************
**************************************************************************/
/* Set method for GObject properties */
purple_status_set_property(GObject *obj, guint param_id, const GValue *value,
PurpleStatus *status = PURPLE_STATUS(obj);
PurpleStatusPrivate *priv = purple_status_get_instance_private(status);
priv->status_type = g_value_get_pointer(value);
priv->presence = g_value_get_object(value);
purple_status_set_active(status, g_value_get_boolean(value));
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
/* Get method for GObject properties */
purple_status_get_property(GObject *obj, guint param_id, GValue *value,
PurpleStatus *status = PURPLE_STATUS(obj);
g_value_set_pointer(value, purple_status_get_status_type(status));
g_value_set_object(value, purple_status_get_presence(status));
g_value_set_boolean(value, purple_status_is_active(status));
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
/* GObject initialization function */
purple_status_init(PurpleStatus *status)
PurpleStatusPrivate *priv = purple_status_get_instance_private(status);
g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
(GDestroyNotify)purple_value_free);
/* Called when done constructing */
purple_status_constructed(GObject *object)
PurpleStatusPrivate *priv = purple_status_get_instance_private(PURPLE_STATUS(object));
G_OBJECT_CLASS(purple_status_parent_class)->constructed(object);
for (l = purple_status_type_get_attrs(priv->status_type); l != NULL; l = l->next)
PurpleStatusAttribute *attr = (PurpleStatusAttribute *)l->data;
GValue *value = purple_status_attribute_get_value(attr);
GValue *new_value = purple_value_dup(value);
g_hash_table_insert(priv->attr_values,
(char *)purple_status_attribute_get_id(attr),
* GObject finalize function
* TODO: If the PurpleStatus is in a PurplePresence, then
* remove it from the PurplePresence?
purple_status_finalize(GObject *obj)
PurpleStatusPrivate *priv = purple_status_get_instance_private(PURPLE_STATUS(obj));
g_hash_table_destroy(priv->attr_values);
G_OBJECT_CLASS(purple_status_parent_class)->finalize(obj);
/* Class initializer function */
purple_status_class_init(PurpleStatusClass *klass)
GObjectClass *obj_class = G_OBJECT_CLASS(klass);
obj_class->finalize = purple_status_finalize;
obj_class->constructed = purple_status_constructed;
obj_class->get_property = purple_status_get_property;
obj_class->set_property = purple_status_set_property;
properties[PROP_STATUS_TYPE] = g_param_spec_pointer("status-type",
"The PurpleStatusType of the status.",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
properties[PROP_PRESENCE] = g_param_spec_object("presence", "Presence",
"The presence that the status belongs to.",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
properties[PROP_ACTIVE] = g_param_spec_boolean("active", "Active",
"Whether the status is active or not.", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties(obj_class, PROP_LAST, properties);
purple_status_new(PurpleStatusType *status_type, PurplePresence *presence)
g_return_val_if_fail(status_type != NULL, NULL);
g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL);
return g_object_new(PURPLE_TYPE_STATUS,
"status-type", status_type,
/**************************************************************************
**************************************************************************/
score_pref_changed_cb(const char *name, PurplePrefType type,
gconstpointer value, gpointer data)
int index = GPOINTER_TO_INT(data);
primitive_scores[index] = GPOINTER_TO_INT(value);
purple_statuses_get_handle(void) {
purple_statuses_init(void)
void *handle = purple_statuses_get_handle();
purple_prefs_add_none("/purple/status");
purple_prefs_add_none("/purple/status/scores");
purple_prefs_add_int("/purple/status/scores/offline",
primitive_scores[PURPLE_STATUS_OFFLINE]);
purple_prefs_add_int("/purple/status/scores/available",
primitive_scores[PURPLE_STATUS_AVAILABLE]);
purple_prefs_add_int("/purple/status/scores/invisible",
primitive_scores[PURPLE_STATUS_INVISIBLE]);
purple_prefs_add_int("/purple/status/scores/away",
primitive_scores[PURPLE_STATUS_AWAY]);
purple_prefs_add_int("/purple/status/scores/extended_away",
primitive_scores[PURPLE_STATUS_EXTENDED_AWAY]);
purple_prefs_add_int("/purple/status/scores/idle",
primitive_scores[SCORE_IDLE]);
purple_prefs_add_int("/purple/status/scores/idle_time",
primitive_scores[SCORE_IDLE_TIME]);
purple_prefs_add_int("/purple/status/scores/offline_msg",
primitive_scores[SCORE_OFFLINE_MESSAGE]);
purple_prefs_connect_callback(handle, "/purple/status/scores/offline",
GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
purple_prefs_connect_callback(handle, "/purple/status/scores/available",
GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
purple_prefs_connect_callback(handle, "/purple/status/scores/invisible",
GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
purple_prefs_connect_callback(handle, "/purple/status/scores/away",
GINT_TO_POINTER(PURPLE_STATUS_AWAY));
purple_prefs_connect_callback(handle, "/purple/status/scores/extended_away",
GINT_TO_POINTER(PURPLE_STATUS_EXTENDED_AWAY));
purple_prefs_connect_callback(handle, "/purple/status/scores/idle",
GINT_TO_POINTER(SCORE_IDLE));
purple_prefs_connect_callback(handle, "/purple/status/scores/idle_time",
GINT_TO_POINTER(SCORE_IDLE_TIME));
purple_prefs_connect_callback(handle, "/purple/status/scores/offline_msg",
GINT_TO_POINTER(SCORE_OFFLINE_MESSAGE));
purple_prefs_trigger_callback("/purple/status/scores/offline");
purple_prefs_trigger_callback("/purple/status/scores/available");
purple_prefs_trigger_callback("/purple/status/scores/invisible");
purple_prefs_trigger_callback("/purple/status/scores/away");
purple_prefs_trigger_callback("/purple/status/scores/extended_away");
purple_prefs_trigger_callback("/purple/status/scores/idle");
purple_prefs_trigger_callback("/purple/status/scores/idle_time");
purple_prefs_trigger_callback("/purple/status/scores/offline_msg");
purple_statuses_uninit(void)
purple_prefs_disconnect_by_handle(purple_prefs_get_handle());
/**************************************************************************/
/**************************************************************************/
purple_attrs_from_vargs(va_list args)
GHashTable *attrs = g_hash_table_new(g_str_hash, g_str_equal);
while ((id = va_arg(args, gchar *)) != NULL)
gpointer data = va_arg(args, gpointer);
g_hash_table_insert(attrs, id, data);