pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Rip out "only" list support from our Windows untar code.
release-2.x.y
2014-03-01, Mark Doliner
a9504b165b27
Rip out "only" list support from our Windows untar code.
We don't use it, and it's easier for me to rip it out than try to
figure out if my change broke the if statement here.
/**
* @file status.c Status API
* @ingroup core
*/
/* 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
*/
#define _PURPLE_STATUS_C_
#include
"internal.h"
#include
"blist.h"
#include
"core.h"
#include
"dbus-maybe.h"
#include
"debug.h"
#include
"notify.h"
#include
"prefs.h"
#include
"status.h"
/**
* A type of status.
*/
struct
_PurpleStatusType
{
PurpleStatusPrimitive
primitive
;
char
*
id
;
char
*
name
;
char
*
primary_attr_id
;
gboolean
saveable
;
gboolean
user_settable
;
gboolean
independent
;
GList
*
attrs
;
};
/**
* A status attribute.
*/
struct
_PurpleStatusAttr
{
char
*
id
;
char
*
name
;
PurpleValue
*
value_type
;
};
/**
* A list of statuses.
*/
struct
_PurplePresence
{
PurplePresenceContext
context
;
gboolean
idle
;
time_t
idle_time
;
time_t
login_time
;
GList
*
statuses
;
GHashTable
*
status_table
;
PurpleStatus
*
active_status
;
union
{
PurpleAccount
*
account
;
struct
{
PurpleConversation
*
conv
;
char
*
user
;
}
chat
;
struct
{
PurpleAccount
*
account
;
char
*
name
;
PurpleBuddy
*
buddy
;
}
buddy
;
}
u
;
};
/**
* An active status.
*/
struct
_PurpleStatus
{
PurpleStatusType
*
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 PurpleValue.
*/
GHashTable
*
attr_values
;
};
typedef
struct
{
PurpleAccount
*
account
;
char
*
name
;
}
PurpleStatusBuddyKey
;
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"
)
},
};
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
);
PURPLE_DBUS_REGISTER_POINTER
(
status_type
,
PurpleStatusType
);
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
);
}
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
,
PurpleValue
*
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 */
purple_status_type_add_attr
(
status_type
,
attr_id
,
attr_name
,
attr_value
);
va_start
(
args
,
attr_value
);
purple_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_free
(
status_type
->
primary_attr_id
);
g_list_foreach
(
status_type
->
attrs
,
(
GFunc
)
purple_status_attr_destroy
,
NULL
);
g_list_free
(
status_type
->
attrs
);
PURPLE_DBUS_UNREGISTER_POINTER
(
status_type
);
g_free
(
status_type
);
}
void
purple_status_type_set_primary_attr
(
PurpleStatusType
*
status_type
,
const
char
*
id
)
{
g_return_if_fail
(
status_type
!=
NULL
);
g_free
(
status_type
->
primary_attr_id
);
status_type
->
primary_attr_id
=
g_strdup
(
id
);
}
void
purple_status_type_add_attr
(
PurpleStatusType
*
status_type
,
const
char
*
id
,
const
char
*
name
,
PurpleValue
*
value
)
{
PurpleStatusAttr
*
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_attr_new
(
id
,
name
,
value
);
status_type
->
attrs
=
g_list_append
(
status_type
->
attrs
,
attr
);
}
void
purple_status_type_add_attrs_vargs
(
PurpleStatusType
*
status_type
,
va_list
args
)
{
const
char
*
id
,
*
name
;
PurpleValue
*
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
,
PurpleValue
*
);
g_return_if_fail
(
value
!=
NULL
);
purple_status_type_add_attr
(
status_type
,
id
,
name
,
value
);
}
}
void
purple_status_type_add_attrs
(
PurpleStatusType
*
status_type
,
const
char
*
id
,
const
char
*
name
,
PurpleValue
*
value
,
...)
{
va_list
args
;
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
);
/* Add the first attribute */
purple_status_type_add_attr
(
status_type
,
id
,
name
,
value
);
va_start
(
args
,
value
);
purple_status_type_add_attrs_vargs
(
status_type
,
args
);
va_end
(
args
);
}
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
);
}
const
char
*
purple_status_type_get_primary_attr
(
const
PurpleStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
NULL
);
return
status_type
->
primary_attr_id
;
}
PurpleStatusAttr
*
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
)
{
PurpleStatusAttr
*
attr
=
(
PurpleStatusAttr
*
)
l
->
data
;
if
(
purple_strequal
(
purple_status_attr_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
;
}
/**************************************************************************
* PurpleStatusAttr API
**************************************************************************/
PurpleStatusAttr
*
purple_status_attr_new
(
const
char
*
id
,
const
char
*
name
,
PurpleValue
*
value_type
)
{
PurpleStatusAttr
*
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
(
PurpleStatusAttr
,
1
);
PURPLE_DBUS_REGISTER_POINTER
(
attr
,
PurpleStatusAttr
);
attr
->
id
=
g_strdup
(
id
);
attr
->
name
=
g_strdup
(
name
);
attr
->
value_type
=
value_type
;
return
attr
;
}
void
purple_status_attr_destroy
(
PurpleStatusAttr
*
attr
)
{
g_return_if_fail
(
attr
!=
NULL
);
g_free
(
attr
->
id
);
g_free
(
attr
->
name
);
purple_value_destroy
(
attr
->
value_type
);
PURPLE_DBUS_UNREGISTER_POINTER
(
attr
);
g_free
(
attr
);
}
const
char
*
purple_status_attr_get_id
(
const
PurpleStatusAttr
*
attr
)
{
g_return_val_if_fail
(
attr
!=
NULL
,
NULL
);
return
attr
->
id
;
}
const
char
*
purple_status_attr_get_name
(
const
PurpleStatusAttr
*
attr
)
{
g_return_val_if_fail
(
attr
!=
NULL
,
NULL
);
return
attr
->
name
;
}
PurpleValue
*
purple_status_attr_get_value
(
const
PurpleStatusAttr
*
attr
)
{
g_return_val_if_fail
(
attr
!=
NULL
,
NULL
);
return
attr
->
value_type
;
}
/**************************************************************************
* PurpleStatus API
**************************************************************************/
PurpleStatus
*
purple_status_new
(
PurpleStatusType
*
status_type
,
PurplePresence
*
presence
)
{
PurpleStatus
*
status
;
GList
*
l
;
g_return_val_if_fail
(
status_type
!=
NULL
,
NULL
);
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
status
=
g_new0
(
PurpleStatus
,
1
);
PURPLE_DBUS_REGISTER_POINTER
(
status
,
PurpleStatus
);
status
->
type
=
status_type
;
status
->
presence
=
presence
;
status
->
attr_values
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
NULL
,
(
GDestroyNotify
)
purple_value_destroy
);
for
(
l
=
purple_status_type_get_attrs
(
status_type
);
l
!=
NULL
;
l
=
l
->
next
)
{
PurpleStatusAttr
*
attr
=
(
PurpleStatusAttr
*
)
l
->
data
;
PurpleValue
*
value
=
purple_status_attr_get_value
(
attr
);
PurpleValue
*
new_value
=
purple_value_dup
(
value
);
g_hash_table_insert
(
status
->
attr_values
,
(
char
*
)
purple_status_attr_get_id
(
attr
),
new_value
);
}
return
status
;
}
/*
* TODO: If the PurpleStatus is in a PurplePresence, then
* remove it from the PurplePresence?
*/
void
purple_status_destroy
(
PurpleStatus
*
status
)
{
g_return_if_fail
(
status
!=
NULL
);
g_hash_table_destroy
(
status
->
attr_values
);
PURPLE_DBUS_UNREGISTER_POINTER
(
status
);
g_free
(
status
);
}
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"
))
{
time_t
current_time
=
time
(
NULL
);
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_free
(
tmp
);
g_free
(
logtmp
);
}
}
static
void
notify_status_update
(
PurplePresence
*
presence
,
PurpleStatus
*
old_status
,
PurpleStatus
*
new_status
)
{
PurplePresenceContext
context
=
purple_presence_get_context
(
presence
);
if
(
context
==
PURPLE_PRESENCE_CONTEXT_ACCOUNT
)
{
PurpleAccount
*
account
=
purple_presence_get_account
(
presence
);
PurpleAccountUiOps
*
ops
=
purple_accounts_get_ui_ops
();
if
(
purple_account_get_enabled
(
account
,
purple_core_get_ui
()))
purple_prpl_change_account_status
(
account
,
old_status
,
new_status
);
if
(
ops
!=
NULL
&&
ops
->
status_changed
!=
NULL
)
{
ops
->
status_changed
(
account
,
new_status
);
}
}
else
if
(
context
==
PURPLE_PRESENCE_CONTEXT_BUDDY
)
{
notify_buddy_status_update
(
purple_presence_get_buddy
(
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
))
old_status
->
active
=
FALSE
;
presence
->
active_status
=
status
;
}
else
old_status
=
NULL
;
notify_status_update
(
presence
,
old_status
,
status
);
}
void
purple_status_set_active
(
PurpleStatus
*
status
,
gboolean
active
)
{
purple_status_set_active_with_attrs_list
(
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 accounts.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
)
{
GList
*
attrs
=
NULL
;
const
gchar
*
id
;
gpointer
data
;
while
((
id
=
va_arg
(
args
,
const
char
*
))
!=
NULL
)
{
attrs
=
g_list_append
(
attrs
,
(
char
*
)
id
);
data
=
va_arg
(
args
,
void
*
);
attrs
=
g_list_append
(
attrs
,
data
);
}
purple_status_set_active_with_attrs_list
(
status
,
active
,
attrs
);
g_list_free
(
attrs
);
}
void
purple_status_set_active_with_attrs_list
(
PurpleStatus
*
status
,
gboolean
active
,
GList
*
attrs
)
{
gboolean
changed
=
FALSE
;
GList
*
l
;
GList
*
specified_attr_ids
=
NULL
;
PurpleStatusType
*
status_type
;
g_return_if_fail
(
status
!=
NULL
);
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
(
status
->
active
!=
active
)
{
changed
=
TRUE
;
}
status
->
active
=
active
;
/* Set any attributes */
l
=
attrs
;
while
(
l
!=
NULL
)
{
const
gchar
*
id
;
PurpleValue
*
value
;
id
=
l
->
data
;
l
=
l
->
next
;
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
,
status
->
type
->
name
);
/* Skip over the data and move on to the next attribute */
l
=
l
->
next
;
continue
;
}
specified_attr_ids
=
g_list_prepend
(
specified_attr_ids
,
(
gpointer
)
id
);
if
(
value
->
type
==
PURPLE_TYPE_STRING
)
{
const
gchar
*
string_data
=
l
->
data
;
l
=
l
->
next
;
if
(
purple_strequal
(
string_data
,
value
->
data
.
string_data
))
continue
;
purple_status_set_attr_string
(
status
,
id
,
string_data
);
changed
=
TRUE
;
}
else
if
(
value
->
type
==
PURPLE_TYPE_INT
)
{
int
int_data
=
GPOINTER_TO_INT
(
l
->
data
);
l
=
l
->
next
;
if
(
int_data
==
value
->
data
.
int_data
)
continue
;
purple_status_set_attr_int
(
status
,
id
,
int_data
);
changed
=
TRUE
;
}
else
if
(
value
->
type
==
PURPLE_TYPE_BOOLEAN
)
{
gboolean
boolean_data
=
GPOINTER_TO_INT
(
l
->
data
);
l
=
l
->
next
;
if
(
boolean_data
==
value
->
data
.
boolean_data
)
continue
;
purple_status_set_attr_boolean
(
status
,
id
,
boolean_data
);
changed
=
TRUE
;
}
else
{
/* We don't know what the data is--skip over it */
l
=
l
->
next
;
}
}
/* Reset any unspecified attributes to their default value */
status_type
=
purple_status_get_type
(
status
);
l
=
purple_status_type_get_attrs
(
status_type
);
while
(
l
!=
NULL
)
{
PurpleStatusAttr
*
attr
;
attr
=
l
->
data
;
l
=
l
->
next
;
if
(
!
g_list_find_custom
(
specified_attr_ids
,
attr
->
id
,
(
GCompareFunc
)
strcmp
))
{
PurpleValue
*
default_value
;
default_value
=
purple_status_attr_get_value
(
attr
);
if
(
default_value
->
type
==
PURPLE_TYPE_STRING
)
{
const
char
*
cur
=
purple_status_get_attr_string
(
status
,
attr
->
id
);
const
char
*
def
=
purple_value_get_string
(
default_value
);
if
((
cur
==
NULL
&&
def
==
NULL
)
||
(
cur
!=
NULL
&&
def
!=
NULL
&&
!
strcmp
(
cur
,
def
)))
{
continue
;
}
purple_status_set_attr_string
(
status
,
attr
->
id
,
def
);
}
else
if
(
default_value
->
type
==
PURPLE_TYPE_INT
)
{
int
cur
=
purple_status_get_attr_int
(
status
,
attr
->
id
);
int
def
=
purple_value_get_int
(
default_value
);
if
(
cur
==
def
)
continue
;
purple_status_set_attr_int
(
status
,
attr
->
id
,
def
);
}
else
if
(
default_value
->
type
==
PURPLE_TYPE_BOOLEAN
)
{
gboolean
cur
=
purple_status_get_attr_boolean
(
status
,
attr
->
id
);
gboolean
def
=
purple_value_get_boolean
(
default_value
);
if
(
cur
==
def
)
continue
;
purple_status_set_attr_boolean
(
status
,
attr
->
id
,
def
);
}
changed
=
TRUE
;
}
}
g_list_free
(
specified_attr_ids
);
if
(
!
changed
)
return
;
status_has_changed
(
status
);
}
void
purple_status_set_attr_boolean
(
PurpleStatus
*
status
,
const
char
*
id
,
gboolean
value
)
{
PurpleValue
*
attr_value
;
g_return_if_fail
(
status
!=
NULL
);
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
(
purple_value_get_type
(
attr_value
)
==
PURPLE_TYPE_BOOLEAN
);
purple_value_set_boolean
(
attr_value
,
value
);
}
void
purple_status_set_attr_int
(
PurpleStatus
*
status
,
const
char
*
id
,
int
value
)
{
PurpleValue
*
attr_value
;
g_return_if_fail
(
status
!=
NULL
);
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
(
purple_value_get_type
(
attr_value
)
==
PURPLE_TYPE_INT
);
purple_value_set_int
(
attr_value
,
value
);
}
void
purple_status_set_attr_string
(
PurpleStatus
*
status
,
const
char
*
id
,
const
char
*
value
)
{
PurpleValue
*
attr_value
;
g_return_if_fail
(
status
!=
NULL
);
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_type
(
status
)));
return
;
}
g_return_if_fail
(
purple_value_get_type
(
attr_value
)
==
PURPLE_TYPE_STRING
);
/* XXX: Check if the value has actually changed. If it has, and the status
* is active, should this trigger 'status_has_changed'? */
purple_value_set_string
(
attr_value
,
value
);
}
PurpleStatusType
*
purple_status_get_type
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
status
->
type
;
}
PurplePresence
*
purple_status_get_presence
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
status
->
presence
;
}
const
char
*
purple_status_get_id
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
purple_status_type_get_id
(
purple_status_get_type
(
status
));
}
const
char
*
purple_status_get_name
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
purple_status_type_get_name
(
purple_status_get_type
(
status
));
}
gboolean
purple_status_is_independent
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
purple_status_type_is_independent
(
purple_status_get_type
(
status
));
}
gboolean
purple_status_is_exclusive
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
purple_status_type_is_exclusive
(
purple_status_get_type
(
status
));
}
gboolean
purple_status_is_available
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
purple_status_type_is_available
(
purple_status_get_type
(
status
));
}
gboolean
purple_status_is_active
(
const
PurpleStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
status
->
active
;
}
gboolean
purple_status_is_online
(
const
PurpleStatus
*
status
)
{
PurpleStatusPrimitive
primitive
;
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
primitive
=
purple_status_type_get_primitive
(
purple_status_get_type
(
status
));
return
(
primitive
!=
PURPLE_STATUS_UNSET
&&
primitive
!=
PURPLE_STATUS_OFFLINE
);
}
PurpleValue
*
purple_status_get_attr_value
(
const
PurpleStatus
*
status
,
const
char
*
id
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
g_return_val_if_fail
(
id
!=
NULL
,
NULL
);
return
(
PurpleValue
*
)
g_hash_table_lookup
(
status
->
attr_values
,
id
);
}
gboolean
purple_status_get_attr_boolean
(
const
PurpleStatus
*
status
,
const
char
*
id
)
{
const
PurpleValue
*
value
;
g_return_val_if_fail
(
status
!=
NULL
,
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
(
purple_value_get_type
(
value
)
==
PURPLE_TYPE_BOOLEAN
,
FALSE
);
return
purple_value_get_boolean
(
value
);
}
int
purple_status_get_attr_int
(
const
PurpleStatus
*
status
,
const
char
*
id
)
{
const
PurpleValue
*
value
;
g_return_val_if_fail
(
status
!=
NULL
,
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
(
purple_value_get_type
(
value
)
==
PURPLE_TYPE_INT
,
0
);
return
purple_value_get_int
(
value
);
}
const
char
*
purple_status_get_attr_string
(
const
PurpleStatus
*
status
,
const
char
*
id
)
{
const
PurpleValue
*
value
;
g_return_val_if_fail
(
status
!=
NULL
,
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
(
purple_value_get_type
(
value
)
==
PURPLE_TYPE_STRING
,
NULL
);
return
purple_value_get_string
(
value
);
}
gint
purple_status_compare
(
const
PurpleStatus
*
status1
,
const
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_type
(
status1
);
type2
=
purple_status_get_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
;
}
/**************************************************************************
* PurplePresence API
**************************************************************************/
PurplePresence
*
purple_presence_new
(
PurplePresenceContext
context
)
{
PurplePresence
*
presence
;
g_return_val_if_fail
(
context
!=
PURPLE_PRESENCE_CONTEXT_UNSET
,
NULL
);
presence
=
g_new0
(
PurplePresence
,
1
);
PURPLE_DBUS_REGISTER_POINTER
(
presence
,
PurplePresence
);
presence
->
context
=
context
;
presence
->
status_table
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
return
presence
;
}
PurplePresence
*
purple_presence_new_for_account
(
PurpleAccount
*
account
)
{
PurplePresence
*
presence
=
NULL
;
g_return_val_if_fail
(
account
!=
NULL
,
NULL
);
presence
=
purple_presence_new
(
PURPLE_PRESENCE_CONTEXT_ACCOUNT
);
presence
->
u
.
account
=
account
;
presence
->
statuses
=
purple_prpl_get_statuses
(
account
,
presence
);
return
presence
;
}
PurplePresence
*
purple_presence_new_for_conv
(
PurpleConversation
*
conv
)
{
PurplePresence
*
presence
;
g_return_val_if_fail
(
conv
!=
NULL
,
NULL
);
presence
=
purple_presence_new
(
PURPLE_PRESENCE_CONTEXT_CONV
);
presence
->
u
.
chat
.
conv
=
conv
;
/* presence->statuses = purple_prpl_get_statuses(conv->account, presence); ? */
return
presence
;
}
PurplePresence
*
purple_presence_new_for_buddy
(
PurpleBuddy
*
buddy
)
{
PurplePresence
*
presence
;
PurpleAccount
*
account
;
g_return_val_if_fail
(
buddy
!=
NULL
,
NULL
);
account
=
purple_buddy_get_account
(
buddy
);
presence
=
purple_presence_new
(
PURPLE_PRESENCE_CONTEXT_BUDDY
);
presence
->
u
.
buddy
.
name
=
g_strdup
(
purple_buddy_get_name
(
buddy
));
presence
->
u
.
buddy
.
account
=
account
;
presence
->
statuses
=
purple_prpl_get_statuses
(
account
,
presence
);
presence
->
u
.
buddy
.
buddy
=
buddy
;
return
presence
;
}
void
purple_presence_destroy
(
PurplePresence
*
presence
)
{
g_return_if_fail
(
presence
!=
NULL
);
if
(
purple_presence_get_context
(
presence
)
==
PURPLE_PRESENCE_CONTEXT_BUDDY
)
{
g_free
(
presence
->
u
.
buddy
.
name
);
}
else
if
(
purple_presence_get_context
(
presence
)
==
PURPLE_PRESENCE_CONTEXT_CONV
)
{
g_free
(
presence
->
u
.
chat
.
user
);
}
g_list_foreach
(
presence
->
statuses
,
(
GFunc
)
purple_status_destroy
,
NULL
);
g_list_free
(
presence
->
statuses
);
g_hash_table_destroy
(
presence
->
status_table
);
PURPLE_DBUS_UNREGISTER_POINTER
(
presence
);
g_free
(
presence
);
}
void
purple_presence_add_status
(
PurplePresence
*
presence
,
PurpleStatus
*
status
)
{
g_return_if_fail
(
presence
!=
NULL
);
g_return_if_fail
(
status
!=
NULL
);
presence
->
statuses
=
g_list_append
(
presence
->
statuses
,
status
);
g_hash_table_insert
(
presence
->
status_table
,
g_strdup
(
purple_status_get_id
(
status
)),
status
);
}
void
purple_presence_add_list
(
PurplePresence
*
presence
,
GList
*
source_list
)
{
GList
*
l
;
g_return_if_fail
(
presence
!=
NULL
);
g_return_if_fail
(
source_list
!=
NULL
);
for
(
l
=
source_list
;
l
!=
NULL
;
l
=
l
->
next
)
purple_presence_add_status
(
presence
,
(
PurpleStatus
*
)
l
->
data
);
}
void
purple_presence_set_status_active
(
PurplePresence
*
presence
,
const
char
*
status_id
,
gboolean
active
)
{
PurpleStatus
*
status
;
g_return_if_fail
(
presence
!=
NULL
);
g_return_if_fail
(
status_id
!=
NULL
);
status
=
purple_presence_get_status
(
presence
,
status_id
);
g_return_if_fail
(
status
!=
NULL
);
/* TODO: Should we do the following? */
/* g_return_if_fail(active == status->active); */
if
(
purple_status_is_exclusive
(
status
))
{
if
(
!
active
)
{
purple_debug_warning
(
"status"
,
"Attempted to set a non-independent status "
"(%s) inactive. Only independent statuses "
"can be specifically marked inactive."
,
status_id
);
return
;
}
}
purple_status_set_active
(
status
,
active
);
}
void
purple_presence_switch_status
(
PurplePresence
*
presence
,
const
char
*
status_id
)
{
purple_presence_set_status_active
(
presence
,
status_id
,
TRUE
);
}
static
void
update_buddy_idle
(
PurpleBuddy
*
buddy
,
PurplePresence
*
presence
,
time_t
current_time
,
gboolean
old_idle
,
gboolean
idle
)
{
PurpleBlistUiOps
*
ops
=
purple_blist_get_ui_ops
();
PurpleAccount
*
account
=
purple_buddy_get_account
(
buddy
);
if
(
!
old_idle
&&
idle
)
{
if
(
purple_prefs_get_bool
(
"/purple/logging/log_system"
))
{
PurpleLog
*
log
=
purple_account_get_log
(
account
,
FALSE
);
if
(
log
!=
NULL
)
{
char
*
tmp
,
*
tmp2
;
tmp
=
g_strdup_printf
(
_
(
"%s became idle"
),
purple_buddy_get_alias
(
buddy
));
tmp2
=
g_markup_escape_text
(
tmp
,
-1
);
g_free
(
tmp
);
purple_log_write
(
log
,
PURPLE_MESSAGE_SYSTEM
,
purple_buddy_get_alias
(
buddy
),
current_time
,
tmp2
);
g_free
(
tmp2
);
}
}
}
else
if
(
old_idle
&&
!
idle
)
{
if
(
purple_prefs_get_bool
(
"/purple/logging/log_system"
))
{
PurpleLog
*
log
=
purple_account_get_log
(
account
,
FALSE
);
if
(
log
!=
NULL
)
{
char
*
tmp
,
*
tmp2
;
tmp
=
g_strdup_printf
(
_
(
"%s became unidle"
),
purple_buddy_get_alias
(
buddy
));
tmp2
=
g_markup_escape_text
(
tmp
,
-1
);
g_free
(
tmp
);
purple_log_write
(
log
,
PURPLE_MESSAGE_SYSTEM
,
purple_buddy_get_alias
(
buddy
),
current_time
,
tmp2
);
g_free
(
tmp2
);
}
}
}
if
(
old_idle
!=
idle
)
purple_signal_emit
(
purple_blist_get_handle
(),
"buddy-idle-changed"
,
buddy
,
old_idle
,
idle
);
purple_contact_invalidate_priority_buddy
(
purple_buddy_get_contact
(
buddy
));
/* Should this be done here? It'd perhaps make more sense to
* connect to buddy-[un]idle signals and update from there
*/
if
(
ops
!=
NULL
&&
ops
->
update
!=
NULL
)
ops
->
update
(
purple_get_blist
(),
(
PurpleBlistNode
*
)
buddy
);
}
void
purple_presence_set_idle
(
PurplePresence
*
presence
,
gboolean
idle
,
time_t
idle_time
)
{
gboolean
old_idle
;
time_t
current_time
;
g_return_if_fail
(
presence
!=
NULL
);
if
(
presence
->
idle
==
idle
&&
presence
->
idle_time
==
idle_time
)
return
;
old_idle
=
presence
->
idle
;
presence
->
idle
=
idle
;
presence
->
idle_time
=
(
idle
?
idle_time
:
0
);
current_time
=
time
(
NULL
);
if
(
purple_presence_get_context
(
presence
)
==
PURPLE_PRESENCE_CONTEXT_BUDDY
)
{
update_buddy_idle
(
purple_presence_get_buddy
(
presence
),
presence
,
current_time
,
old_idle
,
idle
);
}
else
if
(
purple_presence_get_context
(
presence
)
==
PURPLE_PRESENCE_CONTEXT_ACCOUNT
)
{
PurpleAccount
*
account
;
PurpleConnection
*
gc
=
NULL
;
PurplePlugin
*
prpl
=
NULL
;
PurplePluginProtocolInfo
*
prpl_info
=
NULL
;
account
=
purple_presence_get_account
(
presence
);
if
(
purple_prefs_get_bool
(
"/purple/logging/log_system"
))
{
PurpleLog
*
log
=
purple_account_get_log
(
account
,
FALSE
);
if
(
log
!=
NULL
)
{
char
*
msg
,
*
tmp
;
if
(
idle
)
tmp
=
g_strdup_printf
(
_
(
"+++ %s became idle"
),
purple_account_get_username
(
account
));
else
tmp
=
g_strdup_printf
(
_
(
"+++ %s became unidle"
),
purple_account_get_username
(
account
));
msg
=
g_markup_escape_text
(
tmp
,
-1
);
g_free
(
tmp
);
purple_log_write
(
log
,
PURPLE_MESSAGE_SYSTEM
,
purple_account_get_username
(
account
),
(
idle
?
idle_time
:
current_time
),
msg
);
g_free
(
msg
);
}
}
gc
=
purple_account_get_connection
(
account
);
if
(
gc
)
prpl
=
purple_connection_get_prpl
(
gc
);
if
(
PURPLE_CONNECTION_IS_CONNECTED
(
gc
)
&&
prpl
!=
NULL
)
prpl_info
=
PURPLE_PLUGIN_PROTOCOL_INFO
(
prpl
);
if
(
prpl_info
&&
prpl_info
->
set_idle
)
prpl_info
->
set_idle
(
gc
,
(
idle
?
(
current_time
-
idle_time
)
:
0
));
}
}
void
purple_presence_set_login_time
(
PurplePresence
*
presence
,
time_t
login_time
)
{
g_return_if_fail
(
presence
!=
NULL
);
if
(
presence
->
login_time
==
login_time
)
return
;
presence
->
login_time
=
login_time
;
}
PurplePresenceContext
purple_presence_get_context
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
PURPLE_PRESENCE_CONTEXT_UNSET
);
return
presence
->
context
;
}
PurpleAccount
*
purple_presence_get_account
(
const
PurplePresence
*
presence
)
{
PurplePresenceContext
context
;
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
context
=
purple_presence_get_context
(
presence
);
g_return_val_if_fail
(
context
==
PURPLE_PRESENCE_CONTEXT_ACCOUNT
||
context
==
PURPLE_PRESENCE_CONTEXT_BUDDY
,
NULL
);
return
presence
->
u
.
account
;
}
PurpleConversation
*
purple_presence_get_conversation
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
g_return_val_if_fail
(
purple_presence_get_context
(
presence
)
==
PURPLE_PRESENCE_CONTEXT_CONV
,
NULL
);
return
presence
->
u
.
chat
.
conv
;
}
const
char
*
purple_presence_get_chat_user
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
g_return_val_if_fail
(
purple_presence_get_context
(
presence
)
==
PURPLE_PRESENCE_CONTEXT_CONV
,
NULL
);
return
presence
->
u
.
chat
.
user
;
}
PurpleBuddy
*
purple_presence_get_buddy
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
g_return_val_if_fail
(
purple_presence_get_context
(
presence
)
==
PURPLE_PRESENCE_CONTEXT_BUDDY
,
NULL
);
return
presence
->
u
.
buddy
.
buddy
;
}
GList
*
purple_presence_get_statuses
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
return
presence
->
statuses
;
}
PurpleStatus
*
purple_presence_get_status
(
const
PurplePresence
*
presence
,
const
char
*
status_id
)
{
PurpleStatus
*
status
;
GList
*
l
=
NULL
;
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
g_return_val_if_fail
(
status_id
!=
NULL
,
NULL
);
/* What's the purpose of this hash table? */
status
=
(
PurpleStatus
*
)
g_hash_table_lookup
(
presence
->
status_table
,
status_id
);
if
(
status
==
NULL
)
{
for
(
l
=
purple_presence_get_statuses
(
presence
);
l
!=
NULL
&&
status
==
NULL
;
l
=
l
->
next
)
{
PurpleStatus
*
temp_status
=
l
->
data
;
if
(
purple_strequal
(
status_id
,
purple_status_get_id
(
temp_status
)))
status
=
temp_status
;
}
if
(
status
!=
NULL
)
g_hash_table_insert
(
presence
->
status_table
,
g_strdup
(
purple_status_get_id
(
status
)),
status
);
}
return
status
;
}
PurpleStatus
*
purple_presence_get_active_status
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
return
presence
->
active_status
;
}
gboolean
purple_presence_is_available
(
const
PurplePresence
*
presence
)
{
PurpleStatus
*
status
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
status
=
purple_presence_get_active_status
(
presence
);
return
((
status
!=
NULL
&&
purple_status_is_available
(
status
))
&&
!
purple_presence_is_idle
(
presence
));
}
gboolean
purple_presence_is_online
(
const
PurplePresence
*
presence
)
{
PurpleStatus
*
status
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
if
((
status
=
purple_presence_get_active_status
(
presence
))
==
NULL
)
return
FALSE
;
return
purple_status_is_online
(
status
);
}
gboolean
purple_presence_is_status_active
(
const
PurplePresence
*
presence
,
const
char
*
status_id
)
{
PurpleStatus
*
status
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
status_id
!=
NULL
,
FALSE
);
status
=
purple_presence_get_status
(
presence
,
status_id
);
return
(
status
!=
NULL
&&
purple_status_is_active
(
status
));
}
gboolean
purple_presence_is_status_primitive_active
(
const
PurplePresence
*
presence
,
PurpleStatusPrimitive
primitive
)
{
GList
*
l
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
primitive
!=
PURPLE_STATUS_UNSET
,
FALSE
);
for
(
l
=
purple_presence_get_statuses
(
presence
);
l
!=
NULL
;
l
=
l
->
next
)
{
PurpleStatus
*
temp_status
=
l
->
data
;
PurpleStatusType
*
type
=
purple_status_get_type
(
temp_status
);
if
(
purple_status_type_get_primitive
(
type
)
==
primitive
&&
purple_status_is_active
(
temp_status
))
return
TRUE
;
}
return
FALSE
;
}
gboolean
purple_presence_is_idle
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
return
purple_presence_is_online
(
presence
)
&&
presence
->
idle
;
}
time_t
purple_presence_get_idle_time
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
0
);
return
presence
->
idle_time
;
}
time_t
purple_presence_get_login_time
(
const
PurplePresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
0
);
return
purple_presence_is_online
(
presence
)
?
presence
->
login_time
:
0
;
}
static
int
purple_presence_compute_score
(
const
PurplePresence
*
presence
)
{
GList
*
l
;
int
score
=
0
;
for
(
l
=
purple_presence_get_statuses
(
presence
);
l
!=
NULL
;
l
=
l
->
next
)
{
PurpleStatus
*
status
=
(
PurpleStatus
*
)
l
->
data
;
PurpleStatusType
*
type
=
purple_status_get_type
(
status
);
if
(
purple_status_is_active
(
status
))
{
score
+=
primitive_scores
[
purple_status_type_get_primitive
(
type
)];
if
(
!
purple_status_is_online
(
status
))
{
PurpleBuddy
*
b
=
purple_presence_get_buddy
(
presence
);
if
(
b
&&
purple_account_supports_offline_message
(
purple_buddy_get_account
(
b
),
b
))
score
+=
primitive_scores
[
SCORE_OFFLINE_MESSAGE
];
}
}
}
score
+=
purple_account_get_int
(
purple_presence_get_account
(
presence
),
"score"
,
0
);
if
(
purple_presence_is_idle
(
presence
))
score
+=
primitive_scores
[
SCORE_IDLE
];
return
score
;
}
gint
purple_presence_compare
(
const
PurplePresence
*
presence1
,
const
PurplePresence
*
presence2
)
{
time_t
idle_time_1
,
idle_time_2
;
int
score1
=
0
,
score2
=
0
;
if
(
presence1
==
presence2
)
return
0
;
else
if
(
presence1
==
NULL
)
return
1
;
else
if
(
presence2
==
NULL
)
return
-1
;
if
(
purple_presence_is_online
(
presence1
)
&&
!
purple_presence_is_online
(
presence2
))
return
-1
;
else
if
(
purple_presence_is_online
(
presence2
)
&&
!
purple_presence_is_online
(
presence1
))
return
1
;
/* Compute the score of the first set of statuses. */
score1
=
purple_presence_compute_score
(
presence1
);
/* Compute the score of the second set of statuses. */
score2
=
purple_presence_compute_score
(
presence2
);
idle_time_1
=
time
(
NULL
)
-
purple_presence_get_idle_time
(
presence1
);
idle_time_2
=
time
(
NULL
)
-
purple_presence_get_idle_time
(
presence2
);
if
(
idle_time_1
>
idle_time_2
)
score1
+=
primitive_scores
[
SCORE_IDLE_TIME
];
else
if
(
idle_time_1
<
idle_time_2
)
score2
+=
primitive_scores
[
SCORE_IDLE_TIME
];
if
(
score1
<
score2
)
return
1
;
else
if
(
score1
>
score2
)
return
-1
;
return
0
;
}
/**************************************************************************
* 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_status_get_handle
(
void
)
{
static
int
handle
;
return
&
handle
;
}
void
purple_status_init
(
void
)
{
void
*
handle
=
purple_status_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/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/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/offline_msg"
);
}
void
purple_status_uninit
(
void
)
{
purple_prefs_disconnect_by_handle
(
purple_prefs_get_handle
());
}