pidgin/pidgin

Hide common_sockaddr_t as it needs to be removed but it's causing issues now

As mentioned in https://reviews.imfreedom.org/r/14/ this is my current fix for the `common_sockaddr_t` problem. And that is to just hide. By hiding it, we make the core network api and bonjour uses of it independent which means we can swap the out individually with smaller review requests.

Hide common_sockaddr_t as it needs to be removed but it's causing issues now

Reviewed at https://reviews.imfreedom.org/r/15/
/* 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 <glib/gi18n-lib.h>
#include "internal.h"
#include "purpleprivate.h"
#include "buddylist.h"
#include "core.h"
#include "debug.h"
#include "notify.h"
#include "prefs.h"
#include "status.h"
typedef struct _PurpleStatusPrivate PurpleStatusPrivate;
/*
* A type of status.
*/
struct _PurpleStatusType
{
int box_count;
PurpleStatusPrimitive primitive;
char *id;
char *name;
gboolean saveable;
gboolean user_settable;
gboolean independent;
GList *attrs;
};
/*
* A status attribute.
*/
struct _PurpleStatusAttribute
{
char *id;
char *name;
GValue *value_type;
};
/**
* PurpleStatus:
*
* 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
* other random info).
*
* See <link linkend="libpurple-presence">Presence API</link>
*/
struct _PurpleStatus
{
GObject parent;
};
/*
* Private data for PurpleStatus
*/
struct _PurpleStatusPrivate
{
PurpleStatusType *status_type;
PurplePresence *presence;
gboolean active;
/*
* 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.
*/
GHashTable *attr_values;
};
/* GObject property enums */
enum
{
PROP_0,
PROP_STATUS_TYPE,
PROP_PRESENCE,
PROP_ACTIVE,
PROP_LAST
};
typedef struct
{
PurpleAccount *account;
char *name;
} PurpleStatusBuddyKey;
static GParamSpec *properties[PROP_LAST];
G_DEFINE_TYPE_WITH_PRIVATE(PurpleStatus, purple_status, G_TYPE_OBJECT);
static int primitive_scores[] =
{
0, /* unset */
-500, /* offline */
100, /* available */
-75, /* unavailable */
-50, /* invisible */
-100, /* away */
-200, /* extended away */
-400, /* mobile */
0, /* tune */
0, /* mood */
-10, /* idle, special case. */
-5, /* idle time, special case. */
10 /* Offline messageable */
};
#define SCORE_IDLE 9
#define SCORE_IDLE_TIME 10
#define SCORE_OFFLINE_MESSAGE 11
/**************************************************************************
* PurpleStatusPrimitive API
**************************************************************************/
static struct PurpleStatusPrimitiveMap
{
PurpleStatusPrimitive type;
const char *id;
const char *name;
} 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") },
};
int *
_purple_statuses_get_primitive_scores(void)
{
return primitive_scores;
}
const char *
purple_primitive_get_id_from_type(PurpleStatusPrimitive type)
{
int i;
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;
}
const char *
purple_primitive_get_name_from_type(PurpleStatusPrimitive type)
{
int i;
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);
}
PurpleStatusPrimitive
purple_primitive_get_type_from_id(const char *id)
{
int i;
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;
}
/**************************************************************************
* PurpleStatusType API
**************************************************************************/
PurpleStatusType *
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;
if (id != NULL)
status_type->id = g_strdup(id);
else
status_type->id = g_strdup(purple_primitive_get_id_from_type(primitive));
if (name != NULL)
status_type->name = g_strdup(name);
else
status_type->name = g_strdup(purple_primitive_get_name_from_type(primitive));
return status_type;
}
PurpleStatusType *
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,
user_settable, FALSE);
}
static void
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);
}
static void
status_type_add_attrs_vargs(PurpleStatusType *status_type, va_list args)
{
const char *id, *name;
GValue *value;
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);
}
}
PurpleStatusType *
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;
va_list args;
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);
va_end(args);
return status_type;
}
void
purple_status_type_destroy(PurpleStatusType *status_type)
{
g_return_if_fail(status_type != NULL);
g_free(status_type->id);
g_free(status_type->name);
g_list_free_full(status_type->attrs,
(GDestroyNotify)purple_status_attribute_destroy);
g_free(status_type);
}
PurpleStatusPrimitive
purple_status_type_get_primitive(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, PURPLE_STATUS_UNSET);
return status_type->primitive;
}
const char *
purple_status_type_get_id(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, NULL);
return status_type->id;
}
const char *
purple_status_type_get_name(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, NULL);
return status_type->name;
}
gboolean
purple_status_type_is_saveable(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, FALSE);
return status_type->saveable;
}
gboolean
purple_status_type_is_user_settable(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, FALSE);
return status_type->user_settable;
}
gboolean
purple_status_type_is_independent(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, FALSE);
return status_type->independent;
}
gboolean
purple_status_type_is_exclusive(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, FALSE);
return !status_type->independent;
}
gboolean
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);
}
PurpleStatusAttribute *
purple_status_type_get_attr(const PurpleStatusType *status_type, const char *id)
{
GList *l;
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))
return attr;
}
return NULL;
}
GList *
purple_status_type_get_attrs(const PurpleStatusType *status_type)
{
g_return_val_if_fail(status_type != NULL, NULL);
return status_type->attrs;
}
const PurpleStatusType *
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))
return status_type;
status_types = status_types->next;
}
return NULL;
}
/**************************************************************************
* PurpleStatusAttribute API
**************************************************************************/
PurpleStatusAttribute *
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->id = g_strdup(id);
attr->name = g_strdup(name);
attr->value_type = value_type;
return attr;
}
void
purple_status_attribute_destroy(PurpleStatusAttribute *attr)
{
g_return_if_fail(attr != NULL);
g_free(attr->id);
g_free(attr->name);
purple_value_free(attr->value_type);
g_free(attr);
}
const char *
purple_status_attribute_get_id(const PurpleStatusAttribute *attr)
{
g_return_val_if_fail(attr != NULL, NULL);
return attr->id;
}
const char *
purple_status_attribute_get_name(const PurpleStatusAttribute *attr)
{
g_return_val_if_fail(attr != NULL, NULL);
return attr->name;
}
GValue *
purple_status_attribute_get_value(const PurpleStatusAttribute *attr)
{
g_return_val_if_fail(attr != NULL, NULL);
return attr->value_type;
}
/**************************************************************************
* PurpleStatus API
**************************************************************************/
static void
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);
char *tmp, *logtmp;
PurpleLog *log;
if (old_status != NULL)
{
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);
}
else
{
/* 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);
}
else
{
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);
if (log != NULL)
{
purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
current_time, logtmp);
}
g_date_time_unref(current_time);
g_free(tmp);
g_free(logtmp);
}
}
static void
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,
new_status);
}
}
static void
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);
priv->active = FALSE;
g_object_notify_by_pspec(G_OBJECT(old_status),
properties[PROP_ACTIVE]);
}
}
else
old_status = NULL;
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);
}
static void
status_set_attr_boolean(PurpleStatus *status, const char *id,
gboolean value)
{
GValue *attr_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_BOOLEAN);
g_value_set_boolean(attr_value, value);
}
static void
status_set_attr_int(PurpleStatus *status, const char *id, int value)
{
GValue *attr_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);
}
static void
status_set_attr_string(PurpleStatus *status, const char *id,
const char *value)
{
GValue *attr_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);
/* 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 "
"this!\n", id,
purple_status_type_get_name(purple_status_get_status_type(status)));
return;
}
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);
}
void
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.
*/
void
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);
}
void
purple_status_set_active_with_attrs_dict(PurpleStatus *status, gboolean active,
GHashTable *attrs)
{
PurpleStatusPrivate *priv = NULL;
gboolean changed = FALSE;
GHashTableIter iter;
gchar *id;
gpointer data;
GList *l;
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));
return;
}
if (priv->active != active)
{
changed = TRUE;
}
priv->active = active;
/* Set any attributes */
g_hash_table_iter_init(&iter, attrs);
while (g_hash_table_iter_next(&iter, (gpointer *)&id, (gpointer *)&data)) {
GValue *value;
value = purple_status_get_attr_value(status, id);
if (value == NULL)
{
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 */
continue;
}
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)))
continue;
status_set_attr_string(status, id, string_data);
changed = TRUE;
}
else if (G_VALUE_TYPE(value) == G_TYPE_INT)
{
int int_data = GPOINTER_TO_INT(data);
if (int_data == g_value_get_int(value))
continue;
status_set_attr_int(status, id, int_data);
changed = TRUE;
}
else if (G_VALUE_TYPE(value) == G_TYPE_BOOLEAN)
{
gboolean boolean_data = GPOINTER_TO_INT(data);
if (boolean_data == g_value_get_boolean(value))
continue;
status_set_attr_boolean(status, id, boolean_data);
changed = TRUE;
}
}
/* Reset any unspecified attributes to their default value */
status_type = purple_status_get_status_type(status);
l = purple_status_type_get_attrs(status_type);
while (l != NULL) {
PurpleStatusAttribute *attr;
attr = l->data;
l = l->next;
if (!g_list_find_custom(specified_attr_ids, attr->id, (GCompareFunc)strcmp)) {
GValue *default_value;
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)) {
continue;
}
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);
if (cur == def)
continue;
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);
if (cur == def)
continue;
status_set_attr_boolean(status, attr->id, def);
}
changed = TRUE;
}
}
g_list_free(specified_attr_ids);
if (!changed)
return;
status_has_changed(status);
}
PurpleStatusType *
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;
}
PurplePresence *
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);
return priv->presence;
}
const char *
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));
}
const char *
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));
}
gboolean
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));
}
gboolean
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));
}
gboolean
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));
}
gboolean
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);
return priv->active;
}
gboolean
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);
}
GValue *
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);
}
gboolean
purple_status_get_attr_boolean(PurpleStatus *status, const char *id)
{
const GValue *value;
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)
return FALSE;
g_return_val_if_fail(G_VALUE_TYPE(value) == G_TYPE_BOOLEAN, FALSE);
return g_value_get_boolean(value);
}
int
purple_status_get_attr_int(PurpleStatus *status, const char *id)
{
const GValue *value;
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)
return 0;
g_return_val_if_fail(G_VALUE_TYPE(value) == G_TYPE_INT, 0);
return g_value_get_int(value);
}
const char *
purple_status_get_attr_string(PurpleStatus *status, const char *id)
{
const GValue *value;
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)
return NULL;
g_return_val_if_fail(G_VALUE_TYPE(value) == G_TYPE_STRING, NULL);
return g_value_get_string(value);
}
gint
purple_status_compare(PurpleStatus *status1, PurpleStatus *status2)
{
PurpleStatusType *type1, *type2;
int score1 = 0, score2 = 0;
if ((status1 == NULL && status2 == NULL) ||
(status1 == status2))
{
return 0;
}
else if (status1 == NULL)
return 1;
else if (status2 == NULL)
return -1;
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)];
if (score1 > score2)
return -1;
else if (score1 < score2)
return 1;
return 0;
}
/**************************************************************************
* 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++;
return status_type;
}
static void
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);
}
GType
purple_status_type_get_type(void)
{
static GType type = 0;
if (type == 0) {
type = g_boxed_type_register_static("PurpleStatusType",
(GBoxedCopyFunc)purple_status_type_ref,
(GBoxedFreeFunc)purple_status_type_unref);
}
return type;
}
/**************************************************************************
* 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,
status_attr->name,
purple_value_dup(status_attr->value_type));
}
GType
purple_status_attribute_get_type(void)
{
static GType type = 0;
if (type == 0) {
type = g_boxed_type_register_static("PurpleStatusAttribute",
(GBoxedCopyFunc)purple_status_attribute_copy,
(GBoxedFreeFunc)purple_status_attribute_destroy);
}
return type;
}
/**************************************************************************
* GBoxed code for PurpleMood
**************************************************************************/
static PurpleMood *
purple_mood_copy(PurpleMood *mood)
{
PurpleMood *mood_copy;
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);
return mood_copy;
}
static void
purple_mood_free(PurpleMood *mood)
{
g_free((gchar *)mood->mood);
g_free((gchar *)mood->description);
g_free(mood);
}
GType
purple_mood_get_type(void)
{
static GType type = 0;
if (type == 0) {
type = g_boxed_type_register_static("PurpleMood",
(GBoxedCopyFunc)purple_mood_copy,
(GBoxedFreeFunc)purple_mood_free);
}
return type;
}
/**************************************************************************
* GObject code
**************************************************************************/
/* Set method for GObject properties */
static void
purple_status_set_property(GObject *obj, guint param_id, const GValue *value,
GParamSpec *pspec)
{
PurpleStatus *status = PURPLE_STATUS(obj);
PurpleStatusPrivate *priv = purple_status_get_instance_private(status);
switch (param_id) {
case PROP_STATUS_TYPE:
priv->status_type = g_value_get_pointer(value);
break;
case PROP_PRESENCE:
priv->presence = g_value_get_object(value);
break;
case PROP_ACTIVE:
purple_status_set_active(status, g_value_get_boolean(value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* Get method for GObject properties */
static void
purple_status_get_property(GObject *obj, guint param_id, GValue *value,
GParamSpec *pspec)
{
PurpleStatus *status = PURPLE_STATUS(obj);
switch (param_id) {
case PROP_STATUS_TYPE:
g_value_set_pointer(value, purple_status_get_status_type(status));
break;
case PROP_PRESENCE:
g_value_set_object(value, purple_status_get_presence(status));
break;
case PROP_ACTIVE:
g_value_set_boolean(value, purple_status_is_active(status));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
break;
}
}
/* GObject initialization function */
static void
purple_status_init(PurpleStatus *status)
{
PurpleStatusPrivate *priv = purple_status_get_instance_private(status);
priv->attr_values =
g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
(GDestroyNotify)purple_value_free);
}
/* Called when done constructing */
static void
purple_status_constructed(GObject *object)
{
GList *l;
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),
new_value);
}
}
/*
* GObject finalize function
* TODO: If the PurpleStatus is in a PurplePresence, then
* remove it from the PurplePresence?
*/
static void
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 */
static void
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;
/* Setup properties */
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",
"Status type",
"The PurpleStatusType of the status.",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_PRESENCE] = g_param_spec_object("presence", "Presence",
"The presence that the status belongs to.",
PURPLE_TYPE_PRESENCE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
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);
}
PurpleStatus *
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,
"presence", presence,
NULL);
}
/**************************************************************************
* Status subsystem
**************************************************************************/
static void
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);
}
void *
purple_statuses_get_handle(void) {
static int handle;
return &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",
score_pref_changed_cb,
GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
purple_prefs_connect_callback(handle, "/purple/status/scores/available",
score_pref_changed_cb,
GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
purple_prefs_connect_callback(handle, "/purple/status/scores/invisible",
score_pref_changed_cb,
GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
purple_prefs_connect_callback(handle, "/purple/status/scores/away",
score_pref_changed_cb,
GINT_TO_POINTER(PURPLE_STATUS_AWAY));
purple_prefs_connect_callback(handle, "/purple/status/scores/extended_away",
score_pref_changed_cb,
GINT_TO_POINTER(PURPLE_STATUS_EXTENDED_AWAY));
purple_prefs_connect_callback(handle, "/purple/status/scores/idle",
score_pref_changed_cb,
GINT_TO_POINTER(SCORE_IDLE));
purple_prefs_connect_callback(handle, "/purple/status/scores/idle_time",
score_pref_changed_cb,
GINT_TO_POINTER(SCORE_IDLE_TIME));
purple_prefs_connect_callback(handle, "/purple/status/scores/offline_msg",
score_pref_changed_cb,
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");
}
void
purple_statuses_uninit(void)
{
purple_prefs_disconnect_by_handle(purple_prefs_get_handle());
}
/**************************************************************************/
/* Helpers */
/**************************************************************************/
GHashTable *
purple_attrs_from_vargs(va_list args)
{
GHashTable *attrs = g_hash_table_new(g_str_hash, g_str_equal);
gchar *id;
while ((id = va_arg(args, gchar *)) != NULL)
{
gpointer data = va_arg(args, gpointer);
g_hash_table_insert(attrs, id, data);
}
return attrs;
}