pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Remove the Gtk Ticker plugin as it doesn't scale to today's IM networks
2020-08-22, Gary Kramlich
fefaa6596e74
Remove the Gtk Ticker plugin as it doesn't scale to today's IM networks
Remove the ticker plugin as it doesn't scale to todays typical IM usage.
Testing Done:
Compile and install.
Reviewed at https://reviews.imfreedom.org/r/81/
/* 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
;
}