pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
merge of '77693555855fe9cd3215414f79964dba346cc5fa'
gaim
2008-11-12, Richard Laager
1966704b3e42
merge of '77693555855fe9cd3215414f79964dba346cc5fa'
and '19a87e98e5857ad0289f2c760d460f7f1dbbb42d'
/**
* @file status.c Status API
* @ingroup core
*
* gaim
*
* Gaim 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#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
_GaimStatusType
{
GaimStatusPrimitive
primitive
;
char
*
id
;
char
*
name
;
char
*
primary_attr_id
;
gboolean
saveable
;
gboolean
user_settable
;
gboolean
independent
;
GList
*
attrs
;
};
/**
* A status attribute.
*/
struct
_GaimStatusAttr
{
char
*
id
;
char
*
name
;
GaimValue
*
value_type
;
};
/**
* A list of statuses.
*/
struct
_GaimPresence
{
GaimPresenceContext
context
;
gboolean
idle
;
time_t
idle_time
;
time_t
login_time
;
GList
*
statuses
;
GHashTable
*
status_table
;
GaimStatus
*
active_status
;
union
{
GaimAccount
*
account
;
struct
{
GaimConversation
*
conv
;
char
*
user
;
}
chat
;
struct
{
GaimAccount
*
account
;
char
*
name
;
size_t
ref_count
;
GList
*
buddies
;
}
buddy
;
}
u
;
};
/**
* An active status.
*/
struct
_GaimStatus
{
GaimStatusType
*
type
;
GaimPresence
*
presence
;
const
char
*
title
;
gboolean
active
;
GHashTable
*
attr_values
;
};
typedef
struct
{
GaimAccount
*
account
;
char
*
name
;
}
GaimStatusBuddyKey
;
static
int
primitive_scores
[]
=
{
0
,
/* unset */
-500
,
/* offline */
100
,
/* available */
-75
,
/* unavailable */
-50
,
/* invisible */
-100
,
/* away */
-200
,
/* extended away */
-400
,
/* mobile */
-10
,
/* idle, special case. */
-5
/* idle time, special case. */
};
static
GHashTable
*
buddy_presences
=
NULL
;
#define SCORE_IDLE 8
#define SCORE_IDLE_TIME 9
/**************************************************************************
* GaimStatusPrimitive API
**************************************************************************/
static
struct
GaimStatusPrimitiveMap
{
GaimStatusPrimitive
type
;
const
char
*
id
;
const
char
*
name
;
}
const
status_primitive_map
[]
=
{
{
GAIM_STATUS_UNSET
,
"unset"
,
N_
(
"Unset"
)
},
{
GAIM_STATUS_OFFLINE
,
"offline"
,
N_
(
"Offline"
)
},
{
GAIM_STATUS_AVAILABLE
,
"available"
,
N_
(
"Available"
)
},
{
GAIM_STATUS_UNAVAILABLE
,
"unavailable"
,
N_
(
"Unavailable"
)
},
{
GAIM_STATUS_INVISIBLE
,
"invisible"
,
N_
(
"Invisible"
)
},
{
GAIM_STATUS_AWAY
,
"away"
,
N_
(
"Away"
)
},
{
GAIM_STATUS_EXTENDED_AWAY
,
"extended_away"
,
N_
(
"Extended Away"
)
},
{
GAIM_STATUS_MOBILE
,
"mobile"
,
N_
(
"Mobile"
)
}
};
const
char
*
gaim_primitive_get_id_from_type
(
GaimStatusPrimitive
type
)
{
int
i
;
for
(
i
=
0
;
i
<
GAIM_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
*
gaim_primitive_get_name_from_type
(
GaimStatusPrimitive
type
)
{
int
i
;
for
(
i
=
0
;
i
<
GAIM_STATUS_NUM_PRIMITIVES
;
i
++
)
{
if
(
type
==
status_primitive_map
[
i
].
type
)
return
_
(
status_primitive_map
[
i
].
name
);
}
return
_
(
status_primitive_map
[
0
].
name
);
}
GaimStatusPrimitive
gaim_primitive_get_type_from_id
(
const
char
*
id
)
{
int
i
;
g_return_val_if_fail
(
id
!=
NULL
,
GAIM_STATUS_UNSET
);
for
(
i
=
0
;
i
<
GAIM_STATUS_NUM_PRIMITIVES
;
i
++
)
{
if
(
!
strcmp
(
id
,
status_primitive_map
[
i
].
id
))
return
status_primitive_map
[
i
].
type
;
}
return
status_primitive_map
[
0
].
type
;
}
/**************************************************************************
* GaimStatusType API
**************************************************************************/
GaimStatusType
*
gaim_status_type_new_full
(
GaimStatusPrimitive
primitive
,
const
char
*
id
,
const
char
*
name
,
gboolean
saveable
,
gboolean
user_settable
,
gboolean
independent
)
{
GaimStatusType
*
status_type
;
g_return_val_if_fail
(
primitive
!=
GAIM_STATUS_UNSET
,
NULL
);
status_type
=
g_new0
(
GaimStatusType
,
1
);
GAIM_DBUS_REGISTER_POINTER
(
status_type
,
GaimStatusType
);
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
(
gaim_primitive_get_id_from_type
(
primitive
));
if
(
name
!=
NULL
)
status_type
->
name
=
g_strdup
(
name
);
else
status_type
->
name
=
g_strdup
(
gaim_primitive_get_name_from_type
(
primitive
));
return
status_type
;
}
GaimStatusType
*
gaim_status_type_new
(
GaimStatusPrimitive
primitive
,
const
char
*
id
,
const
char
*
name
,
gboolean
user_settable
)
{
g_return_val_if_fail
(
primitive
!=
GAIM_STATUS_UNSET
,
NULL
);
return
gaim_status_type_new_full
(
primitive
,
id
,
name
,
FALSE
,
user_settable
,
FALSE
);
}
GaimStatusType
*
gaim_status_type_new_with_attrs
(
GaimStatusPrimitive
primitive
,
const
char
*
id
,
const
char
*
name
,
gboolean
saveable
,
gboolean
user_settable
,
gboolean
independent
,
const
char
*
attr_id
,
const
char
*
attr_name
,
GaimValue
*
attr_value
,
...)
{
GaimStatusType
*
status_type
;
va_list
args
;
g_return_val_if_fail
(
primitive
!=
GAIM_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
=
gaim_status_type_new_full
(
primitive
,
id
,
name
,
saveable
,
user_settable
,
independent
);
/* Add the first attribute */
gaim_status_type_add_attr
(
status_type
,
attr_id
,
attr_name
,
attr_value
);
va_start
(
args
,
attr_value
);
gaim_status_type_add_attrs_vargs
(
status_type
,
args
);
va_end
(
args
);
return
status_type
;
}
void
gaim_status_type_destroy
(
GaimStatusType
*
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
)
gaim_status_attr_destroy
,
NULL
);
g_list_free
(
status_type
->
attrs
);
GAIM_DBUS_UNREGISTER_POINTER
(
status_type
);
g_free
(
status_type
);
}
void
gaim_status_type_set_primary_attr
(
GaimStatusType
*
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
gaim_status_type_add_attr
(
GaimStatusType
*
status_type
,
const
char
*
id
,
const
char
*
name
,
GaimValue
*
value
)
{
GaimStatusAttr
*
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
=
gaim_status_attr_new
(
id
,
name
,
value
);
status_type
->
attrs
=
g_list_append
(
status_type
->
attrs
,
attr
);
}
void
gaim_status_type_add_attrs_vargs
(
GaimStatusType
*
status_type
,
va_list
args
)
{
const
char
*
id
,
*
name
;
GaimValue
*
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
,
GaimValue
*
);
g_return_if_fail
(
value
!=
NULL
);
gaim_status_type_add_attr
(
status_type
,
id
,
name
,
value
);
}
}
void
gaim_status_type_add_attrs
(
GaimStatusType
*
status_type
,
const
char
*
id
,
const
char
*
name
,
GaimValue
*
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 */
gaim_status_type_add_attr
(
status_type
,
id
,
name
,
value
);
va_start
(
args
,
value
);
gaim_status_type_add_attrs_vargs
(
status_type
,
args
);
va_end
(
args
);
}
GaimStatusPrimitive
gaim_status_type_get_primitive
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
GAIM_STATUS_UNSET
);
return
status_type
->
primitive
;
}
const
char
*
gaim_status_type_get_id
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
NULL
);
return
status_type
->
id
;
}
const
char
*
gaim_status_type_get_name
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
NULL
);
return
status_type
->
name
;
}
gboolean
gaim_status_type_is_saveable
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
FALSE
);
return
status_type
->
saveable
;
}
gboolean
gaim_status_type_is_user_settable
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
FALSE
);
return
status_type
->
user_settable
;
}
gboolean
gaim_status_type_is_independent
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
FALSE
);
return
status_type
->
independent
;
}
gboolean
gaim_status_type_is_exclusive
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
FALSE
);
return
!
status_type
->
independent
;
}
gboolean
gaim_status_type_is_available
(
const
GaimStatusType
*
status_type
)
{
GaimStatusPrimitive
primitive
;
g_return_val_if_fail
(
status_type
!=
NULL
,
FALSE
);
primitive
=
gaim_status_type_get_primitive
(
status_type
);
return
(
primitive
==
GAIM_STATUS_AVAILABLE
);
}
const
char
*
gaim_status_type_get_primary_attr
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
NULL
);
return
status_type
->
primary_attr_id
;
}
GaimStatusAttr
*
gaim_status_type_get_attr
(
const
GaimStatusType
*
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
)
{
GaimStatusAttr
*
attr
=
(
GaimStatusAttr
*
)
l
->
data
;
if
(
!
strcmp
(
gaim_status_attr_get_id
(
attr
),
id
))
return
attr
;
}
return
NULL
;
}
const
GList
*
gaim_status_type_get_attrs
(
const
GaimStatusType
*
status_type
)
{
g_return_val_if_fail
(
status_type
!=
NULL
,
NULL
);
return
status_type
->
attrs
;
}
const
GaimStatusType
*
gaim_status_type_find_with_id
(
GList
*
status_types
,
const
char
*
id
)
{
GaimStatusType
*
status_type
;
g_return_val_if_fail
(
id
!=
NULL
,
NULL
);
while
(
status_types
!=
NULL
)
{
status_type
=
status_types
->
data
;
if
(
!
strcmp
(
id
,
status_type
->
id
))
return
status_type
;
status_types
=
status_types
->
next
;
}
return
NULL
;
}
/**************************************************************************
* GaimStatusAttr API
**************************************************************************/
GaimStatusAttr
*
gaim_status_attr_new
(
const
char
*
id
,
const
char
*
name
,
GaimValue
*
value_type
)
{
GaimStatusAttr
*
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
(
GaimStatusAttr
,
1
);
GAIM_DBUS_REGISTER_POINTER
(
attr
,
GaimStatusAttr
);
attr
->
id
=
g_strdup
(
id
);
attr
->
name
=
g_strdup
(
name
);
attr
->
value_type
=
value_type
;
return
attr
;
}
void
gaim_status_attr_destroy
(
GaimStatusAttr
*
attr
)
{
g_return_if_fail
(
attr
!=
NULL
);
g_free
(
attr
->
id
);
g_free
(
attr
->
name
);
gaim_value_destroy
(
attr
->
value_type
);
GAIM_DBUS_UNREGISTER_POINTER
(
attr
);
g_free
(
attr
);
}
const
char
*
gaim_status_attr_get_id
(
const
GaimStatusAttr
*
attr
)
{
g_return_val_if_fail
(
attr
!=
NULL
,
NULL
);
return
attr
->
id
;
}
const
char
*
gaim_status_attr_get_name
(
const
GaimStatusAttr
*
attr
)
{
g_return_val_if_fail
(
attr
!=
NULL
,
NULL
);
return
attr
->
name
;
}
GaimValue
*
gaim_status_attr_get_value
(
const
GaimStatusAttr
*
attr
)
{
g_return_val_if_fail
(
attr
!=
NULL
,
NULL
);
return
attr
->
value_type
;
}
/**************************************************************************
* GaimStatus API
**************************************************************************/
GaimStatus
*
gaim_status_new
(
GaimStatusType
*
status_type
,
GaimPresence
*
presence
)
{
GaimStatus
*
status
;
const
GList
*
l
;
g_return_val_if_fail
(
status_type
!=
NULL
,
NULL
);
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
status
=
g_new0
(
GaimStatus
,
1
);
GAIM_DBUS_REGISTER_POINTER
(
status
,
GaimStatus
);
status
->
type
=
status_type
;
status
->
presence
=
presence
;
status
->
attr_values
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
(
GDestroyNotify
)
gaim_value_destroy
);
for
(
l
=
gaim_status_type_get_attrs
(
status_type
);
l
!=
NULL
;
l
=
l
->
next
)
{
GaimStatusAttr
*
attr
=
(
GaimStatusAttr
*
)
l
->
data
;
GaimValue
*
value
=
gaim_status_attr_get_value
(
attr
);
GaimValue
*
new_value
=
gaim_value_dup
(
value
);
g_hash_table_insert
(
status
->
attr_values
,
g_strdup
(
gaim_status_attr_get_id
(
attr
)),
new_value
);
}
return
status
;
}
/*
* TODO: If the GaimStatus is in a GaimPresence, then
* remove it from the GaimPresence?
*/
void
gaim_status_destroy
(
GaimStatus
*
status
)
{
g_return_if_fail
(
status
!=
NULL
);
g_hash_table_destroy
(
status
->
attr_values
);
GAIM_DBUS_UNREGISTER_POINTER
(
status
);
g_free
(
status
);
}
static
void
notify_buddy_status_update
(
GaimBuddy
*
buddy
,
GaimPresence
*
presence
,
GaimStatus
*
old_status
,
GaimStatus
*
new_status
)
{
GaimBlistUiOps
*
ops
=
gaim_blist_get_ui_ops
();
if
(
gaim_prefs_get_bool
(
"/core/logging/log_system"
))
{
time_t
current_time
=
time
(
NULL
);
const
char
*
buddy_alias
=
gaim_buddy_get_alias
(
buddy
);
char
*
tmp
;
GaimLog
*
log
;
if
(
old_status
!=
NULL
)
{
tmp
=
g_strdup_printf
(
_
(
"%s changed status from %s to %s"
),
buddy_alias
,
gaim_status_get_name
(
old_status
),
gaim_status_get_name
(
new_status
));
}
else
{
/* old_status == NULL when an independent status is toggled. */
if
(
gaim_status_is_active
(
new_status
))
{
tmp
=
g_strdup_printf
(
_
(
"%s is now %s"
),
buddy_alias
,
gaim_status_get_name
(
new_status
));
}
else
{
tmp
=
g_strdup_printf
(
_
(
"%s is no longer %s"
),
buddy_alias
,
gaim_status_get_name
(
new_status
));
}
}
log
=
gaim_account_get_log
(
buddy
->
account
,
FALSE
);
if
(
log
!=
NULL
)
{
gaim_log_write
(
log
,
GAIM_MESSAGE_SYSTEM
,
buddy_alias
,
current_time
,
tmp
);
}
g_free
(
tmp
);
}
if
(
ops
!=
NULL
&&
ops
->
update
!=
NULL
)
ops
->
update
(
gaim_get_blist
(),
(
GaimBlistNode
*
)
buddy
);
}
static
void
notify_status_update
(
GaimPresence
*
presence
,
GaimStatus
*
old_status
,
GaimStatus
*
new_status
)
{
GaimPresenceContext
context
=
gaim_presence_get_context
(
presence
);
if
(
context
==
GAIM_PRESENCE_CONTEXT_ACCOUNT
)
{
GaimAccount
*
account
=
gaim_presence_get_account
(
presence
);
GaimAccountUiOps
*
ops
=
gaim_accounts_get_ui_ops
();
if
(
gaim_account_get_enabled
(
account
,
gaim_core_get_ui
()))
gaim_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
==
GAIM_PRESENCE_CONTEXT_BUDDY
)
{
const
GList
*
l
;
for
(
l
=
gaim_presence_get_buddies
(
presence
);
l
!=
NULL
;
l
=
l
->
next
)
{
notify_buddy_status_update
((
GaimBuddy
*
)
l
->
data
,
presence
,
old_status
,
new_status
);
}
}
}
static
void
status_has_changed
(
GaimStatus
*
status
)
{
GaimPresence
*
presence
;
GaimStatus
*
old_status
;
presence
=
gaim_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
(
gaim_status_is_exclusive
(
status
))
{
old_status
=
gaim_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
gaim_status_set_active
(
GaimStatus
*
status
,
gboolean
active
)
{
gaim_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 gaim_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
gaim_status_set_active_with_attrs
(
GaimStatus
*
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
);
}
gaim_status_set_active_with_attrs_list
(
status
,
active
,
attrs
);
g_list_free
(
attrs
);
}
void
gaim_status_set_active_with_attrs_list
(
GaimStatus
*
status
,
gboolean
active
,
const
GList
*
attrs
)
{
gboolean
changed
=
FALSE
;
const
GList
*
l
;
GList
*
specified_attr_ids
=
NULL
;
GaimStatusType
*
status_type
;
g_return_if_fail
(
status
!=
NULL
);
if
(
!
active
&&
gaim_status_is_exclusive
(
status
))
{
gaim_debug_error
(
"status"
,
"Cannot deactivate an exclusive status (%s).
\n
"
,
gaim_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
;
GaimValue
*
value
;
id
=
l
->
data
;
l
=
l
->
next
;
value
=
gaim_status_get_attr_value
(
status
,
id
);
if
(
value
==
NULL
)
{
gaim_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
==
GAIM_TYPE_STRING
)
{
const
gchar
*
string_data
=
l
->
data
;
l
=
l
->
next
;
if
(((
string_data
==
NULL
)
&&
(
value
->
data
.
string_data
==
NULL
))
||
((
string_data
!=
NULL
)
&&
(
value
->
data
.
string_data
!=
NULL
)
&&
!
strcmp
(
string_data
,
value
->
data
.
string_data
)))
{
continue
;
}
gaim_status_set_attr_string
(
status
,
id
,
string_data
);
changed
=
TRUE
;
}
else
if
(
value
->
type
==
GAIM_TYPE_INT
)
{
int
int_data
=
GPOINTER_TO_INT
(
l
->
data
);
l
=
l
->
next
;
if
(
int_data
==
value
->
data
.
int_data
)
continue
;
gaim_status_set_attr_int
(
status
,
id
,
int_data
);
changed
=
TRUE
;
}
else
if
(
value
->
type
==
GAIM_TYPE_BOOLEAN
)
{
gboolean
boolean_data
=
GPOINTER_TO_INT
(
l
->
data
);
l
=
l
->
next
;
if
(
boolean_data
==
value
->
data
.
boolean_data
)
continue
;
gaim_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
=
gaim_status_get_type
(
status
);
l
=
gaim_status_type_get_attrs
(
status_type
);
while
(
l
!=
NULL
)
{
GaimStatusAttr
*
attr
;
attr
=
l
->
data
;
if
(
!
g_list_find_custom
(
specified_attr_ids
,
attr
->
id
,
(
GCompareFunc
)
strcmp
))
{
GaimValue
*
default_value
;
default_value
=
gaim_status_attr_get_value
(
attr
);
if
(
default_value
->
type
==
GAIM_TYPE_STRING
)
gaim_status_set_attr_string
(
status
,
attr
->
id
,
gaim_value_get_string
(
default_value
));
else
if
(
default_value
->
type
==
GAIM_TYPE_INT
)
gaim_status_set_attr_int
(
status
,
attr
->
id
,
gaim_value_get_int
(
default_value
));
else
if
(
default_value
->
type
==
GAIM_TYPE_BOOLEAN
)
gaim_status_set_attr_boolean
(
status
,
attr
->
id
,
gaim_value_get_boolean
(
default_value
));
changed
=
TRUE
;
}
l
=
l
->
next
;
}
g_list_free
(
specified_attr_ids
);
if
(
!
changed
)
return
;
status_has_changed
(
status
);
}
void
gaim_status_set_attr_boolean
(
GaimStatus
*
status
,
const
char
*
id
,
gboolean
value
)
{
GaimValue
*
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
=
gaim_status_get_attr_value
(
status
,
id
);
g_return_if_fail
(
attr_value
!=
NULL
);
g_return_if_fail
(
gaim_value_get_type
(
attr_value
)
==
GAIM_TYPE_BOOLEAN
);
gaim_value_set_boolean
(
attr_value
,
value
);
}
void
gaim_status_set_attr_int
(
GaimStatus
*
status
,
const
char
*
id
,
int
value
)
{
GaimValue
*
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
=
gaim_status_get_attr_value
(
status
,
id
);
g_return_if_fail
(
attr_value
!=
NULL
);
g_return_if_fail
(
gaim_value_get_type
(
attr_value
)
==
GAIM_TYPE_INT
);
gaim_value_set_int
(
attr_value
,
value
);
}
void
gaim_status_set_attr_string
(
GaimStatus
*
status
,
const
char
*
id
,
const
char
*
value
)
{
GaimValue
*
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
=
gaim_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
)
{
gaim_debug_error
(
"status"
,
"Attempted to set status attribute '%s' for "
"status '%s', which is not legal. Fix "
"this!
\n
"
,
id
,
gaim_status_type_get_name
(
gaim_status_get_type
(
status
)));
return
;
}
g_return_if_fail
(
gaim_value_get_type
(
attr_value
)
==
GAIM_TYPE_STRING
);
gaim_value_set_string
(
attr_value
,
value
);
}
GaimStatusType
*
gaim_status_get_type
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
status
->
type
;
}
GaimPresence
*
gaim_status_get_presence
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
status
->
presence
;
}
const
char
*
gaim_status_get_id
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
gaim_status_type_get_id
(
gaim_status_get_type
(
status
));
}
const
char
*
gaim_status_get_name
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
return
gaim_status_type_get_name
(
gaim_status_get_type
(
status
));
}
gboolean
gaim_status_is_independent
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
gaim_status_type_is_independent
(
gaim_status_get_type
(
status
));
}
gboolean
gaim_status_is_exclusive
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
gaim_status_type_is_exclusive
(
gaim_status_get_type
(
status
));
}
gboolean
gaim_status_is_available
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
gaim_status_type_is_available
(
gaim_status_get_type
(
status
));
}
gboolean
gaim_status_is_active
(
const
GaimStatus
*
status
)
{
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
return
status
->
active
;
}
gboolean
gaim_status_is_online
(
const
GaimStatus
*
status
)
{
GaimStatusPrimitive
primitive
;
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
primitive
=
gaim_status_type_get_primitive
(
gaim_status_get_type
(
status
));
return
(
primitive
!=
GAIM_STATUS_UNSET
&&
primitive
!=
GAIM_STATUS_OFFLINE
);
}
GaimValue
*
gaim_status_get_attr_value
(
const
GaimStatus
*
status
,
const
char
*
id
)
{
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
g_return_val_if_fail
(
id
!=
NULL
,
NULL
);
return
(
GaimValue
*
)
g_hash_table_lookup
(
status
->
attr_values
,
id
);
}
gboolean
gaim_status_get_attr_boolean
(
const
GaimStatus
*
status
,
const
char
*
id
)
{
const
GaimValue
*
value
;
g_return_val_if_fail
(
status
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
id
!=
NULL
,
FALSE
);
if
((
value
=
gaim_status_get_attr_value
(
status
,
id
))
==
NULL
)
return
FALSE
;
g_return_val_if_fail
(
gaim_value_get_type
(
value
)
==
GAIM_TYPE_BOOLEAN
,
FALSE
);
return
gaim_value_get_boolean
(
value
);
}
int
gaim_status_get_attr_int
(
const
GaimStatus
*
status
,
const
char
*
id
)
{
const
GaimValue
*
value
;
g_return_val_if_fail
(
status
!=
NULL
,
0
);
g_return_val_if_fail
(
id
!=
NULL
,
0
);
if
((
value
=
gaim_status_get_attr_value
(
status
,
id
))
==
NULL
)
return
0
;
g_return_val_if_fail
(
gaim_value_get_type
(
value
)
==
GAIM_TYPE_INT
,
0
);
return
gaim_value_get_int
(
value
);
}
const
char
*
gaim_status_get_attr_string
(
const
GaimStatus
*
status
,
const
char
*
id
)
{
const
GaimValue
*
value
;
g_return_val_if_fail
(
status
!=
NULL
,
NULL
);
g_return_val_if_fail
(
id
!=
NULL
,
NULL
);
if
((
value
=
gaim_status_get_attr_value
(
status
,
id
))
==
NULL
)
return
NULL
;
g_return_val_if_fail
(
gaim_value_get_type
(
value
)
==
GAIM_TYPE_STRING
,
NULL
);
return
gaim_value_get_string
(
value
);
}
gint
gaim_status_compare
(
const
GaimStatus
*
status1
,
const
GaimStatus
*
status2
)
{
GaimStatusType
*
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
=
gaim_status_get_type
(
status1
);
type2
=
gaim_status_get_type
(
status2
);
if
(
gaim_status_is_active
(
status1
))
score1
=
primitive_scores
[
gaim_status_type_get_primitive
(
type1
)];
if
(
gaim_status_is_active
(
status2
))
score2
=
primitive_scores
[
gaim_status_type_get_primitive
(
type2
)];
if
(
score1
>
score2
)
return
-1
;
else
if
(
score1
<
score2
)
return
1
;
return
0
;
}
/**************************************************************************
* GaimPresence API
**************************************************************************/
GaimPresence
*
gaim_presence_new
(
GaimPresenceContext
context
)
{
GaimPresence
*
presence
;
g_return_val_if_fail
(
context
!=
GAIM_PRESENCE_CONTEXT_UNSET
,
NULL
);
presence
=
g_new0
(
GaimPresence
,
1
);
GAIM_DBUS_REGISTER_POINTER
(
presence
,
GaimPresence
);
presence
->
context
=
context
;
presence
->
status_table
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
return
presence
;
}
GaimPresence
*
gaim_presence_new_for_account
(
GaimAccount
*
account
)
{
GaimPresence
*
presence
=
NULL
;
g_return_val_if_fail
(
account
!=
NULL
,
NULL
);
presence
=
gaim_presence_new
(
GAIM_PRESENCE_CONTEXT_ACCOUNT
);
presence
->
u
.
account
=
account
;
presence
->
statuses
=
gaim_prpl_get_statuses
(
account
,
presence
);
return
presence
;
}
GaimPresence
*
gaim_presence_new_for_conv
(
GaimConversation
*
conv
)
{
GaimPresence
*
presence
;
g_return_val_if_fail
(
conv
!=
NULL
,
NULL
);
presence
=
gaim_presence_new
(
GAIM_PRESENCE_CONTEXT_CONV
);
presence
->
u
.
chat
.
conv
=
conv
;
/* presence->statuses = gaim_prpl_get_statuses(conv->account, presence); ? */
return
presence
;
}
GaimPresence
*
gaim_presence_new_for_buddy
(
GaimBuddy
*
buddy
)
{
GaimPresence
*
presence
;
GaimStatusBuddyKey
*
key
;
GaimAccount
*
account
;
g_return_val_if_fail
(
buddy
!=
NULL
,
NULL
);
account
=
buddy
->
account
;
key
=
g_new0
(
GaimStatusBuddyKey
,
1
);
key
->
account
=
buddy
->
account
;
key
->
name
=
g_strdup
(
buddy
->
name
);
presence
=
g_hash_table_lookup
(
buddy_presences
,
key
);
if
(
presence
==
NULL
)
{
presence
=
gaim_presence_new
(
GAIM_PRESENCE_CONTEXT_BUDDY
);
presence
->
u
.
buddy
.
name
=
g_strdup
(
buddy
->
name
);
presence
->
u
.
buddy
.
account
=
buddy
->
account
;
presence
->
statuses
=
gaim_prpl_get_statuses
(
buddy
->
account
,
presence
);
g_hash_table_insert
(
buddy_presences
,
key
,
presence
);
}
else
{
g_free
(
key
->
name
);
g_free
(
key
);
}
presence
->
u
.
buddy
.
ref_count
++
;
presence
->
u
.
buddy
.
buddies
=
g_list_append
(
presence
->
u
.
buddy
.
buddies
,
buddy
);
return
presence
;
}
void
gaim_presence_destroy
(
GaimPresence
*
presence
)
{
g_return_if_fail
(
presence
!=
NULL
);
if
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_BUDDY
)
{
GaimStatusBuddyKey
key
;
if
(
presence
->
u
.
buddy
.
ref_count
!=
0
)
return
;
key
.
account
=
presence
->
u
.
buddy
.
account
;
key
.
name
=
presence
->
u
.
buddy
.
name
;
g_hash_table_remove
(
buddy_presences
,
&
key
);
g_free
(
presence
->
u
.
buddy
.
name
);
}
else
if
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_CONV
)
{
g_free
(
presence
->
u
.
chat
.
user
);
}
g_list_foreach
(
presence
->
statuses
,
(
GFunc
)
gaim_status_destroy
,
NULL
);
g_list_free
(
presence
->
statuses
);
g_hash_table_destroy
(
presence
->
status_table
);
GAIM_DBUS_UNREGISTER_POINTER
(
presence
);
g_free
(
presence
);
}
/*
* TODO: Maybe we should cal gaim_presence_destroy() after we
* decrement the ref count? I don't see why we should
* make other places do it manually when we can do it here.
*/
void
gaim_presence_remove_buddy
(
GaimPresence
*
presence
,
GaimBuddy
*
buddy
)
{
g_return_if_fail
(
presence
!=
NULL
);
g_return_if_fail
(
buddy
!=
NULL
);
g_return_if_fail
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_BUDDY
);
if
(
g_list_find
(
presence
->
u
.
buddy
.
buddies
,
buddy
)
!=
NULL
)
{
presence
->
u
.
buddy
.
buddies
=
g_list_remove
(
presence
->
u
.
buddy
.
buddies
,
buddy
);
presence
->
u
.
buddy
.
ref_count
--
;
}
}
void
gaim_presence_add_status
(
GaimPresence
*
presence
,
GaimStatus
*
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
(
gaim_status_get_id
(
status
)),
status
);
}
void
gaim_presence_add_list
(
GaimPresence
*
presence
,
const
GList
*
source_list
)
{
const
GList
*
l
;
g_return_if_fail
(
presence
!=
NULL
);
g_return_if_fail
(
source_list
!=
NULL
);
for
(
l
=
source_list
;
l
!=
NULL
;
l
=
l
->
next
)
gaim_presence_add_status
(
presence
,
(
GaimStatus
*
)
l
->
data
);
}
void
gaim_presence_set_status_active
(
GaimPresence
*
presence
,
const
char
*
status_id
,
gboolean
active
)
{
GaimStatus
*
status
;
g_return_if_fail
(
presence
!=
NULL
);
g_return_if_fail
(
status_id
!=
NULL
);
status
=
gaim_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
(
gaim_status_is_exclusive
(
status
))
{
if
(
!
active
)
{
gaim_debug_warning
(
"status"
,
"Attempted to set a non-independent status "
"(%s) inactive. Only independent statuses "
"can be specifically marked inactive."
,
status_id
);
return
;
}
}
gaim_status_set_active
(
status
,
active
);
}
void
gaim_presence_switch_status
(
GaimPresence
*
presence
,
const
char
*
status_id
)
{
gaim_presence_set_status_active
(
presence
,
status_id
,
TRUE
);
}
static
void
update_buddy_idle
(
GaimBuddy
*
buddy
,
GaimPresence
*
presence
,
time_t
current_time
,
gboolean
old_idle
,
gboolean
idle
)
{
GaimBlistUiOps
*
ops
=
gaim_blist_get_ui_ops
();
if
(
!
old_idle
&&
idle
)
{
if
(
gaim_prefs_get_bool
(
"/core/logging/log_system"
))
{
GaimLog
*
log
=
gaim_account_get_log
(
buddy
->
account
,
FALSE
);
if
(
log
!=
NULL
)
{
char
*
tmp
=
g_strdup_printf
(
_
(
"%s became idle"
),
gaim_buddy_get_alias
(
buddy
));
gaim_log_write
(
log
,
GAIM_MESSAGE_SYSTEM
,
gaim_buddy_get_alias
(
buddy
),
current_time
,
tmp
);
g_free
(
tmp
);
}
}
}
else
if
(
old_idle
&&
!
idle
)
{
if
(
gaim_prefs_get_bool
(
"/core/logging/log_system"
))
{
GaimLog
*
log
=
gaim_account_get_log
(
buddy
->
account
,
FALSE
);
if
(
log
!=
NULL
)
{
char
*
tmp
=
g_strdup_printf
(
_
(
"%s became unidle"
),
gaim_buddy_get_alias
(
buddy
));
gaim_log_write
(
log
,
GAIM_MESSAGE_SYSTEM
,
gaim_buddy_get_alias
(
buddy
),
current_time
,
tmp
);
g_free
(
tmp
);
}
}
}
if
(
old_idle
!=
idle
)
gaim_signal_emit
(
gaim_blist_get_handle
(),
"buddy-idle-changed"
,
buddy
,
old_idle
,
idle
);
gaim_contact_invalidate_priority_buddy
(
gaim_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
(
gaim_get_blist
(),
(
GaimBlistNode
*
)
buddy
);
}
void
gaim_presence_set_idle
(
GaimPresence
*
presence
,
gboolean
idle
,
time_t
idle_time
)
{
gboolean
old_idle
;
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
);
if
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_BUDDY
)
{
const
GList
*
l
;
time_t
current_time
=
time
(
NULL
);
for
(
l
=
gaim_presence_get_buddies
(
presence
);
l
!=
NULL
;
l
=
l
->
next
)
{
update_buddy_idle
((
GaimBuddy
*
)
l
->
data
,
presence
,
current_time
,
old_idle
,
idle
);
}
}
else
if
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_ACCOUNT
)
{
GaimAccount
*
account
;
GaimConnection
*
gc
;
GaimPluginProtocolInfo
*
prpl_info
=
NULL
;
account
=
gaim_presence_get_account
(
presence
);
if
(
gaim_prefs_get_bool
(
"/core/logging/log_system"
))
{
GaimLog
*
log
=
gaim_account_get_log
(
account
,
FALSE
);
if
(
log
!=
NULL
)
{
char
*
msg
;
if
(
idle
)
msg
=
g_strdup_printf
(
_
(
"+++ %s became idle"
),
gaim_account_get_username
(
account
));
else
msg
=
g_strdup_printf
(
_
(
"+++ %s became unidle"
),
gaim_account_get_username
(
account
));
gaim_log_write
(
log
,
GAIM_MESSAGE_SYSTEM
,
gaim_account_get_username
(
account
),
idle_time
,
msg
);
g_free
(
msg
);
}
}
gc
=
gaim_account_get_connection
(
account
);
if
(
gc
!=
NULL
&&
GAIM_CONNECTION_IS_CONNECTED
(
gc
)
&&
gc
->
prpl
!=
NULL
)
prpl_info
=
GAIM_PLUGIN_PROTOCOL_INFO
(
gc
->
prpl
);
if
(
prpl_info
&&
prpl_info
->
set_idle
)
prpl_info
->
set_idle
(
gc
,
(
idle
?
(
time
(
NULL
)
-
idle_time
)
:
0
));
}
}
void
gaim_presence_set_login_time
(
GaimPresence
*
presence
,
time_t
login_time
)
{
g_return_if_fail
(
presence
!=
NULL
);
if
(
presence
->
login_time
==
login_time
)
return
;
presence
->
login_time
=
login_time
;
}
GaimPresenceContext
gaim_presence_get_context
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
GAIM_PRESENCE_CONTEXT_UNSET
);
return
presence
->
context
;
}
GaimAccount
*
gaim_presence_get_account
(
const
GaimPresence
*
presence
)
{
GaimPresenceContext
context
;
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
context
=
gaim_presence_get_context
(
presence
);
g_return_val_if_fail
(
context
==
GAIM_PRESENCE_CONTEXT_ACCOUNT
||
context
==
GAIM_PRESENCE_CONTEXT_BUDDY
,
NULL
);
return
presence
->
u
.
account
;
}
GaimConversation
*
gaim_presence_get_conversation
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
g_return_val_if_fail
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_CONV
,
NULL
);
return
presence
->
u
.
chat
.
conv
;
}
const
char
*
gaim_presence_get_chat_user
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
g_return_val_if_fail
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_CONV
,
NULL
);
return
presence
->
u
.
chat
.
user
;
}
const
GList
*
gaim_presence_get_buddies
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
g_return_val_if_fail
(
gaim_presence_get_context
(
presence
)
==
GAIM_PRESENCE_CONTEXT_BUDDY
,
NULL
);
return
presence
->
u
.
buddy
.
buddies
;
}
const
GList
*
gaim_presence_get_statuses
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
return
presence
->
statuses
;
}
GaimStatus
*
gaim_presence_get_status
(
const
GaimPresence
*
presence
,
const
char
*
status_id
)
{
GaimStatus
*
status
;
const
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
=
(
GaimStatus
*
)
g_hash_table_lookup
(
presence
->
status_table
,
status_id
);
if
(
status
==
NULL
)
{
for
(
l
=
gaim_presence_get_statuses
(
presence
);
l
!=
NULL
&&
status
==
NULL
;
l
=
l
->
next
)
{
GaimStatus
*
temp_status
=
l
->
data
;
if
(
!
strcmp
(
status_id
,
gaim_status_get_id
(
temp_status
)))
status
=
temp_status
;
}
if
(
status
!=
NULL
)
g_hash_table_insert
(
presence
->
status_table
,
g_strdup
(
gaim_status_get_id
(
status
)),
status
);
}
return
status
;
}
GaimStatus
*
gaim_presence_get_active_status
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
NULL
);
return
presence
->
active_status
;
}
gboolean
gaim_presence_is_available
(
const
GaimPresence
*
presence
)
{
GaimStatus
*
status
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
status
=
gaim_presence_get_active_status
(
presence
);
return
((
status
!=
NULL
&&
gaim_status_is_available
(
status
))
&&
!
gaim_presence_is_idle
(
presence
));
}
gboolean
gaim_presence_is_online
(
const
GaimPresence
*
presence
)
{
GaimStatus
*
status
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
if
((
status
=
gaim_presence_get_active_status
(
presence
))
==
NULL
)
return
FALSE
;
return
gaim_status_is_online
(
status
);
}
gboolean
gaim_presence_is_status_active
(
const
GaimPresence
*
presence
,
const
char
*
status_id
)
{
GaimStatus
*
status
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
status_id
!=
NULL
,
FALSE
);
status
=
gaim_presence_get_status
(
presence
,
status_id
);
return
(
status
!=
NULL
&&
gaim_status_is_active
(
status
));
}
gboolean
gaim_presence_is_status_primitive_active
(
const
GaimPresence
*
presence
,
GaimStatusPrimitive
primitive
)
{
GaimStatus
*
status
;
GaimStatusType
*
status_type
;
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
primitive
!=
GAIM_STATUS_UNSET
,
FALSE
);
status
=
gaim_presence_get_active_status
(
presence
);
status_type
=
gaim_status_get_type
(
status
);
if
(
gaim_status_type_get_primitive
(
status_type
)
==
primitive
)
return
TRUE
;
return
FALSE
;
}
gboolean
gaim_presence_is_idle
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
FALSE
);
return
gaim_presence_is_online
(
presence
)
&&
presence
->
idle
;
}
time_t
gaim_presence_get_idle_time
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
0
);
return
presence
->
idle_time
;
}
time_t
gaim_presence_get_login_time
(
const
GaimPresence
*
presence
)
{
g_return_val_if_fail
(
presence
!=
NULL
,
0
);
return
gaim_presence_is_online
(
presence
)
?
presence
->
login_time
:
0
;
}
gint
gaim_presence_compare
(
const
GaimPresence
*
presence1
,
const
GaimPresence
*
presence2
)
{
gboolean
idle1
,
idle2
;
time_t
idle_time_1
,
idle_time_2
;
int
score1
=
0
,
score2
=
0
;
const
GList
*
l
;
if
(
presence1
==
presence2
)
return
0
;
else
if
(
presence1
==
NULL
)
return
1
;
else
if
(
presence2
==
NULL
)
return
-1
;
/* Compute the score of the first set of statuses. */
for
(
l
=
gaim_presence_get_statuses
(
presence1
);
l
!=
NULL
;
l
=
l
->
next
)
{
GaimStatus
*
status
=
(
GaimStatus
*
)
l
->
data
;
GaimStatusType
*
type
=
gaim_status_get_type
(
status
);
if
(
gaim_status_is_active
(
status
))
score1
+=
primitive_scores
[
gaim_status_type_get_primitive
(
type
)];
}
score1
+=
gaim_account_get_int
(
gaim_presence_get_account
(
presence1
),
"score"
,
0
);
/* Compute the score of the second set of statuses. */
for
(
l
=
gaim_presence_get_statuses
(
presence2
);
l
!=
NULL
;
l
=
l
->
next
)
{
GaimStatus
*
status
=
(
GaimStatus
*
)
l
->
data
;
GaimStatusType
*
type
=
gaim_status_get_type
(
status
);
if
(
gaim_status_is_active
(
status
))
score2
+=
primitive_scores
[
gaim_status_type_get_primitive
(
type
)];
}
score2
+=
gaim_account_get_int
(
gaim_presence_get_account
(
presence2
),
"score"
,
0
);
idle1
=
gaim_presence_is_idle
(
presence1
);
idle2
=
gaim_presence_is_idle
(
presence2
);
if
(
idle1
)
score1
+=
primitive_scores
[
SCORE_IDLE
];
if
(
idle2
)
score2
+=
primitive_scores
[
SCORE_IDLE
];
idle_time_1
=
time
(
NULL
)
-
gaim_presence_get_idle_time
(
presence1
);
idle_time_2
=
time
(
NULL
)
-
gaim_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
,
GaimPrefType
type
,
gconstpointer
value
,
gpointer
data
)
{
int
index
=
GPOINTER_TO_INT
(
data
);
primitive_scores
[
index
]
=
GPOINTER_TO_INT
(
value
);
}
static
guint
gaim_buddy_presences_hash
(
gconstpointer
key
)
{
const
GaimStatusBuddyKey
*
me
=
key
;
guint
ret
;
char
*
str
;
str
=
g_strdup_printf
(
"%p%s"
,
me
->
account
,
me
->
name
);
ret
=
g_str_hash
(
str
);
g_free
(
str
);
return
ret
;
}
static
gboolean
gaim_buddy_presences_equal
(
gconstpointer
a
,
gconstpointer
b
)
{
GaimStatusBuddyKey
*
key_a
=
(
GaimStatusBuddyKey
*
)
a
;
GaimStatusBuddyKey
*
key_b
=
(
GaimStatusBuddyKey
*
)
b
;
if
(
key_a
->
account
==
key_b
->
account
&&
!
strcmp
(
key_a
->
name
,
key_b
->
name
))
return
TRUE
;
else
return
FALSE
;
}
static
void
gaim_buddy_presences_key_free
(
gpointer
a
)
{
GaimStatusBuddyKey
*
key
=
(
GaimStatusBuddyKey
*
)
a
;
g_free
(
key
->
name
);
g_free
(
key
);
}
void
*
gaim_status_get_handle
(
void
)
{
static
int
handle
;
return
&
handle
;
}
void
gaim_status_init
(
void
)
{
void
*
handle
=
gaim_status_get_handle
;
gaim_prefs_add_none
(
"/core/status"
);
gaim_prefs_add_none
(
"/core/status/scores"
);
gaim_prefs_add_int
(
"/core/status/scores/offline"
,
primitive_scores
[
GAIM_STATUS_OFFLINE
]);
gaim_prefs_add_int
(
"/core/status/scores/available"
,
primitive_scores
[
GAIM_STATUS_AVAILABLE
]);
gaim_prefs_add_int
(
"/core/status/scores/invisible"
,
primitive_scores
[
GAIM_STATUS_INVISIBLE
]);
gaim_prefs_add_int
(
"/core/status/scores/away"
,
primitive_scores
[
GAIM_STATUS_AWAY
]);
gaim_prefs_add_int
(
"/core/status/scores/extended_away"
,
primitive_scores
[
GAIM_STATUS_EXTENDED_AWAY
]);
gaim_prefs_add_int
(
"/core/status/scores/idle"
,
primitive_scores
[
SCORE_IDLE
]);
gaim_prefs_connect_callback
(
handle
,
"/core/status/scores/offline"
,
score_pref_changed_cb
,
GINT_TO_POINTER
(
GAIM_STATUS_OFFLINE
));
gaim_prefs_connect_callback
(
handle
,
"/core/status/scores/available"
,
score_pref_changed_cb
,
GINT_TO_POINTER
(
GAIM_STATUS_AVAILABLE
));
gaim_prefs_connect_callback
(
handle
,
"/core/status/scores/invisible"
,
score_pref_changed_cb
,
GINT_TO_POINTER
(
GAIM_STATUS_INVISIBLE
));
gaim_prefs_connect_callback
(
handle
,
"/core/status/scores/away"
,
score_pref_changed_cb
,
GINT_TO_POINTER
(
GAIM_STATUS_AWAY
));
gaim_prefs_connect_callback
(
handle
,
"/core/status/scores/extended_away"
,
score_pref_changed_cb
,
GINT_TO_POINTER
(
GAIM_STATUS_EXTENDED_AWAY
));
gaim_prefs_connect_callback
(
handle
,
"/core/status/scores/idle"
,
score_pref_changed_cb
,
GINT_TO_POINTER
(
SCORE_IDLE
));
buddy_presences
=
g_hash_table_new_full
(
gaim_buddy_presences_hash
,
gaim_buddy_presences_equal
,
gaim_buddy_presences_key_free
,
NULL
);
}
void
gaim_status_uninit
(
void
)
{
if
(
buddy_presences
!=
NULL
)
{
g_hash_table_destroy
(
buddy_presences
);
buddy_presences
=
NULL
;
}
}