merge of '0d364079f80c7a3cfcf1dccba283f84ecc5fe329'
[pidgin-git.git] / libpurple / status.c
blob9f7f80f151c40979b5c322cd566bebd1b85fa897
1 /**
2 * @file status.c Status API
3 * @ingroup core
4 */
6 /* purple
8 * Purple is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 #define _PURPLE_STATUS_C_
28 #include "internal.h"
30 #include "blist.h"
31 #include "core.h"
32 #include "dbus-maybe.h"
33 #include "debug.h"
34 #include "notify.h"
35 #include "prefs.h"
36 #include "status.h"
38 /**
39 * A type of status.
41 struct _PurpleStatusType
43 PurpleStatusPrimitive primitive;
45 char *id;
46 char *name;
47 char *primary_attr_id;
49 gboolean saveable;
50 gboolean user_settable;
51 gboolean independent;
53 GList *attrs;
56 /**
57 * A status attribute.
59 struct _PurpleStatusAttr
61 char *id;
62 char *name;
63 PurpleValue *value_type;
66 /**
67 * A list of statuses.
69 struct _PurplePresence
71 PurplePresenceContext context;
73 gboolean idle;
74 time_t idle_time;
75 time_t login_time;
77 GList *statuses;
78 GHashTable *status_table;
80 PurpleStatus *active_status;
82 union
84 PurpleAccount *account;
86 struct
88 PurpleConversation *conv;
89 char *user;
91 } chat;
93 struct
95 PurpleAccount *account;
96 char *name;
97 PurpleBuddy *buddy;
99 } buddy;
101 } u;
105 * An active status.
107 struct _PurpleStatus
109 PurpleStatusType *type;
110 PurplePresence *presence;
112 gboolean active;
115 * The current values of the attributes for this status. The
116 * key is a string containing the name of the attribute. It is
117 * a borrowed reference from the list of attrs in the
118 * PurpleStatusType. The value is a PurpleValue.
120 GHashTable *attr_values;
123 typedef struct
125 PurpleAccount *account;
126 char *name;
127 } PurpleStatusBuddyKey;
129 static int primitive_scores[] =
131 0, /* unset */
132 -500, /* offline */
133 100, /* available */
134 -75, /* unavailable */
135 -50, /* invisible */
136 -100, /* away */
137 -200, /* extended away */
138 -400, /* mobile */
139 0, /* tune */
140 0, /* mood */
141 -10, /* idle, special case. */
142 -5, /* idle time, special case. */
143 10 /* Offline messageable */
146 #define SCORE_IDLE 9
147 #define SCORE_IDLE_TIME 10
148 #define SCORE_OFFLINE_MESSAGE 11
150 /**************************************************************************
151 * PurpleStatusPrimitive API
152 **************************************************************************/
153 static struct PurpleStatusPrimitiveMap
155 PurpleStatusPrimitive type;
156 const char *id;
157 const char *name;
159 } const status_primitive_map[] =
161 { PURPLE_STATUS_UNSET, "unset", N_("Unset") },
162 { PURPLE_STATUS_OFFLINE, "offline", N_("Offline") },
163 { PURPLE_STATUS_AVAILABLE, "available", N_("Available") },
164 { PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") },
165 { PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") },
166 { PURPLE_STATUS_AWAY, "away", N_("Away") },
167 { PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") },
168 { PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") },
169 { PURPLE_STATUS_TUNE, "tune", N_("Listening to music"), },
170 { PURPLE_STATUS_MOOD, "mood", N_("Feeling") },
173 const char *
174 purple_primitive_get_id_from_type(PurpleStatusPrimitive type)
176 int i;
178 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
180 if (type == status_primitive_map[i].type)
181 return status_primitive_map[i].id;
184 return status_primitive_map[0].id;
187 const char *
188 purple_primitive_get_name_from_type(PurpleStatusPrimitive type)
190 int i;
192 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
194 if (type == status_primitive_map[i].type)
195 return _(status_primitive_map[i].name);
198 return _(status_primitive_map[0].name);
201 PurpleStatusPrimitive
202 purple_primitive_get_type_from_id(const char *id)
204 int i;
206 g_return_val_if_fail(id != NULL, PURPLE_STATUS_UNSET);
208 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
210 if (purple_strequal(id, status_primitive_map[i].id))
211 return status_primitive_map[i].type;
214 return status_primitive_map[0].type;
218 /**************************************************************************
219 * PurpleStatusType API
220 **************************************************************************/
221 PurpleStatusType *
222 purple_status_type_new_full(PurpleStatusPrimitive primitive, const char *id,
223 const char *name, gboolean saveable,
224 gboolean user_settable, gboolean independent)
226 PurpleStatusType *status_type;
228 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
230 status_type = g_new0(PurpleStatusType, 1);
231 PURPLE_DBUS_REGISTER_POINTER(status_type, PurpleStatusType);
233 status_type->primitive = primitive;
234 status_type->saveable = saveable;
235 status_type->user_settable = user_settable;
236 status_type->independent = independent;
238 if (id != NULL)
239 status_type->id = g_strdup(id);
240 else
241 status_type->id = g_strdup(purple_primitive_get_id_from_type(primitive));
243 if (name != NULL)
244 status_type->name = g_strdup(name);
245 else
246 status_type->name = g_strdup(purple_primitive_get_name_from_type(primitive));
248 return status_type;
251 PurpleStatusType *
252 purple_status_type_new(PurpleStatusPrimitive primitive, const char *id,
253 const char *name, gboolean user_settable)
255 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
257 return purple_status_type_new_full(primitive, id, name, TRUE,
258 user_settable, FALSE);
261 PurpleStatusType *
262 purple_status_type_new_with_attrs(PurpleStatusPrimitive primitive,
263 const char *id, const char *name,
264 gboolean saveable, gboolean user_settable,
265 gboolean independent, const char *attr_id,
266 const char *attr_name, PurpleValue *attr_value,
267 ...)
269 PurpleStatusType *status_type;
270 va_list args;
272 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
273 g_return_val_if_fail(attr_id != NULL, NULL);
274 g_return_val_if_fail(attr_name != NULL, NULL);
275 g_return_val_if_fail(attr_value != NULL, NULL);
277 status_type = purple_status_type_new_full(primitive, id, name, saveable,
278 user_settable, independent);
280 /* Add the first attribute */
281 purple_status_type_add_attr(status_type, attr_id, attr_name, attr_value);
283 va_start(args, attr_value);
284 purple_status_type_add_attrs_vargs(status_type, args);
285 va_end(args);
287 return status_type;
290 void
291 purple_status_type_destroy(PurpleStatusType *status_type)
293 g_return_if_fail(status_type != NULL);
295 g_free(status_type->id);
296 g_free(status_type->name);
297 g_free(status_type->primary_attr_id);
299 g_list_foreach(status_type->attrs, (GFunc)purple_status_attr_destroy, NULL);
300 g_list_free(status_type->attrs);
302 PURPLE_DBUS_UNREGISTER_POINTER(status_type);
303 g_free(status_type);
306 void
307 purple_status_type_set_primary_attr(PurpleStatusType *status_type, const char *id)
309 g_return_if_fail(status_type != NULL);
311 g_free(status_type->primary_attr_id);
312 status_type->primary_attr_id = g_strdup(id);
315 void
316 purple_status_type_add_attr(PurpleStatusType *status_type, const char *id,
317 const char *name, PurpleValue *value)
319 PurpleStatusAttr *attr;
321 g_return_if_fail(status_type != NULL);
322 g_return_if_fail(id != NULL);
323 g_return_if_fail(name != NULL);
324 g_return_if_fail(value != NULL);
326 attr = purple_status_attr_new(id, name, value);
328 status_type->attrs = g_list_append(status_type->attrs, attr);
331 void
332 purple_status_type_add_attrs_vargs(PurpleStatusType *status_type, va_list args)
334 const char *id, *name;
335 PurpleValue *value;
337 g_return_if_fail(status_type != NULL);
339 while ((id = va_arg(args, const char *)) != NULL)
341 name = va_arg(args, const char *);
342 g_return_if_fail(name != NULL);
344 value = va_arg(args, PurpleValue *);
345 g_return_if_fail(value != NULL);
347 purple_status_type_add_attr(status_type, id, name, value);
351 void
352 purple_status_type_add_attrs(PurpleStatusType *status_type, const char *id,
353 const char *name, PurpleValue *value, ...)
355 va_list args;
357 g_return_if_fail(status_type != NULL);
358 g_return_if_fail(id != NULL);
359 g_return_if_fail(name != NULL);
360 g_return_if_fail(value != NULL);
362 /* Add the first attribute */
363 purple_status_type_add_attr(status_type, id, name, value);
365 va_start(args, value);
366 purple_status_type_add_attrs_vargs(status_type, args);
367 va_end(args);
370 PurpleStatusPrimitive
371 purple_status_type_get_primitive(const PurpleStatusType *status_type)
373 g_return_val_if_fail(status_type != NULL, PURPLE_STATUS_UNSET);
375 return status_type->primitive;
378 const char *
379 purple_status_type_get_id(const PurpleStatusType *status_type)
381 g_return_val_if_fail(status_type != NULL, NULL);
383 return status_type->id;
386 const char *
387 purple_status_type_get_name(const PurpleStatusType *status_type)
389 g_return_val_if_fail(status_type != NULL, NULL);
391 return status_type->name;
394 gboolean
395 purple_status_type_is_saveable(const PurpleStatusType *status_type)
397 g_return_val_if_fail(status_type != NULL, FALSE);
399 return status_type->saveable;
402 gboolean
403 purple_status_type_is_user_settable(const PurpleStatusType *status_type)
405 g_return_val_if_fail(status_type != NULL, FALSE);
407 return status_type->user_settable;
410 gboolean
411 purple_status_type_is_independent(const PurpleStatusType *status_type)
413 g_return_val_if_fail(status_type != NULL, FALSE);
415 return status_type->independent;
418 gboolean
419 purple_status_type_is_exclusive(const PurpleStatusType *status_type)
421 g_return_val_if_fail(status_type != NULL, FALSE);
423 return !status_type->independent;
426 gboolean
427 purple_status_type_is_available(const PurpleStatusType *status_type)
429 PurpleStatusPrimitive primitive;
431 g_return_val_if_fail(status_type != NULL, FALSE);
433 primitive = purple_status_type_get_primitive(status_type);
435 return (primitive == PURPLE_STATUS_AVAILABLE);
438 const char *
439 purple_status_type_get_primary_attr(const PurpleStatusType *status_type)
441 g_return_val_if_fail(status_type != NULL, NULL);
443 return status_type->primary_attr_id;
446 PurpleStatusAttr *
447 purple_status_type_get_attr(const PurpleStatusType *status_type, const char *id)
449 GList *l;
451 g_return_val_if_fail(status_type != NULL, NULL);
452 g_return_val_if_fail(id != NULL, NULL);
454 for (l = status_type->attrs; l != NULL; l = l->next)
456 PurpleStatusAttr *attr = (PurpleStatusAttr *)l->data;
458 if (purple_strequal(purple_status_attr_get_id(attr), id))
459 return attr;
462 return NULL;
465 GList *
466 purple_status_type_get_attrs(const PurpleStatusType *status_type)
468 g_return_val_if_fail(status_type != NULL, NULL);
470 return status_type->attrs;
473 const PurpleStatusType *
474 purple_status_type_find_with_id(GList *status_types, const char *id)
476 PurpleStatusType *status_type;
478 g_return_val_if_fail(id != NULL, NULL);
480 while (status_types != NULL)
482 status_type = status_types->data;
484 if (purple_strequal(id, status_type->id))
485 return status_type;
487 status_types = status_types->next;
490 return NULL;
494 /**************************************************************************
495 * PurpleStatusAttr API
496 **************************************************************************/
497 PurpleStatusAttr *
498 purple_status_attr_new(const char *id, const char *name, PurpleValue *value_type)
500 PurpleStatusAttr *attr;
502 g_return_val_if_fail(id != NULL, NULL);
503 g_return_val_if_fail(name != NULL, NULL);
504 g_return_val_if_fail(value_type != NULL, NULL);
506 attr = g_new0(PurpleStatusAttr, 1);
507 PURPLE_DBUS_REGISTER_POINTER(attr, PurpleStatusAttr);
509 attr->id = g_strdup(id);
510 attr->name = g_strdup(name);
511 attr->value_type = value_type;
513 return attr;
516 void
517 purple_status_attr_destroy(PurpleStatusAttr *attr)
519 g_return_if_fail(attr != NULL);
521 g_free(attr->id);
522 g_free(attr->name);
524 purple_value_destroy(attr->value_type);
526 PURPLE_DBUS_UNREGISTER_POINTER(attr);
527 g_free(attr);
530 const char *
531 purple_status_attr_get_id(const PurpleStatusAttr *attr)
533 g_return_val_if_fail(attr != NULL, NULL);
535 return attr->id;
538 const char *
539 purple_status_attr_get_name(const PurpleStatusAttr *attr)
541 g_return_val_if_fail(attr != NULL, NULL);
543 return attr->name;
546 PurpleValue *
547 purple_status_attr_get_value(const PurpleStatusAttr *attr)
549 g_return_val_if_fail(attr != NULL, NULL);
551 return attr->value_type;
555 /**************************************************************************
556 * PurpleStatus API
557 **************************************************************************/
558 PurpleStatus *
559 purple_status_new(PurpleStatusType *status_type, PurplePresence *presence)
561 PurpleStatus *status;
562 GList *l;
564 g_return_val_if_fail(status_type != NULL, NULL);
565 g_return_val_if_fail(presence != NULL, NULL);
567 status = g_new0(PurpleStatus, 1);
568 PURPLE_DBUS_REGISTER_POINTER(status, PurpleStatus);
570 status->type = status_type;
571 status->presence = presence;
573 status->attr_values =
574 g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
575 (GDestroyNotify)purple_value_destroy);
577 for (l = purple_status_type_get_attrs(status_type); l != NULL; l = l->next)
579 PurpleStatusAttr *attr = (PurpleStatusAttr *)l->data;
580 PurpleValue *value = purple_status_attr_get_value(attr);
581 PurpleValue *new_value = purple_value_dup(value);
583 g_hash_table_insert(status->attr_values,
584 (char *)purple_status_attr_get_id(attr),
585 new_value);
588 return status;
592 * TODO: If the PurpleStatus is in a PurplePresence, then
593 * remove it from the PurplePresence?
595 void
596 purple_status_destroy(PurpleStatus *status)
598 g_return_if_fail(status != NULL);
600 g_hash_table_destroy(status->attr_values);
602 PURPLE_DBUS_UNREGISTER_POINTER(status);
603 g_free(status);
606 static void
607 notify_buddy_status_update(PurpleBuddy *buddy, PurplePresence *presence,
608 PurpleStatus *old_status, PurpleStatus *new_status)
610 if (purple_prefs_get_bool("/purple/logging/log_system"))
612 time_t current_time = time(NULL);
613 const char *buddy_alias = purple_buddy_get_alias(buddy);
614 char *tmp, *logtmp;
615 PurpleLog *log;
617 if (old_status != NULL)
619 tmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias,
620 purple_buddy_get_name(buddy),
621 purple_status_get_name(old_status),
622 purple_status_get_name(new_status));
623 logtmp = g_markup_escape_text(tmp, -1);
625 else
627 /* old_status == NULL when an independent status is toggled. */
629 if (purple_status_is_active(new_status))
631 tmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias,
632 purple_buddy_get_name(buddy),
633 purple_status_get_name(new_status));
634 logtmp = g_markup_escape_text(tmp, -1);
636 else
638 tmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias,
639 purple_buddy_get_name(buddy),
640 purple_status_get_name(new_status));
641 logtmp = g_markup_escape_text(tmp, -1);
645 log = purple_account_get_log(purple_buddy_get_account(buddy), FALSE);
646 if (log != NULL)
648 purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
649 current_time, logtmp);
652 g_free(tmp);
653 g_free(logtmp);
657 static void
658 notify_status_update(PurplePresence *presence, PurpleStatus *old_status,
659 PurpleStatus *new_status)
661 PurplePresenceContext context = purple_presence_get_context(presence);
663 if (context == PURPLE_PRESENCE_CONTEXT_ACCOUNT)
665 PurpleAccount *account = purple_presence_get_account(presence);
666 PurpleAccountUiOps *ops = purple_accounts_get_ui_ops();
668 if (purple_account_get_enabled(account, purple_core_get_ui()))
669 purple_prpl_change_account_status(account, old_status, new_status);
671 if (ops != NULL && ops->status_changed != NULL)
673 ops->status_changed(account, new_status);
676 else if (context == PURPLE_PRESENCE_CONTEXT_BUDDY)
678 notify_buddy_status_update(purple_presence_get_buddy(presence), presence,
679 old_status, new_status);
683 static void
684 status_has_changed(PurpleStatus *status)
686 PurplePresence *presence;
687 PurpleStatus *old_status;
689 presence = purple_status_get_presence(status);
692 * If this status is exclusive, then we must be setting it to "active."
693 * Since we are setting it to active, we want to set the currently
694 * active status to "inactive."
696 if (purple_status_is_exclusive(status))
698 old_status = purple_presence_get_active_status(presence);
699 if (old_status != NULL && (old_status != status))
700 old_status->active = FALSE;
701 presence->active_status = status;
703 else
704 old_status = NULL;
706 notify_status_update(presence, old_status, status);
709 void
710 purple_status_set_active(PurpleStatus *status, gboolean active)
712 purple_status_set_active_with_attrs_list(status, active, NULL);
716 * This used to parse the va_list directly, but now it creates a GList
717 * and passes it to purple_status_set_active_with_attrs_list(). That
718 * function was created because accounts.c needs to pass a GList of
719 * attributes to the status API.
721 void
722 purple_status_set_active_with_attrs(PurpleStatus *status, gboolean active, va_list args)
724 GList *attrs = NULL;
725 const gchar *id;
726 gpointer data;
728 while ((id = va_arg(args, const char *)) != NULL)
730 attrs = g_list_append(attrs, (char *)id);
731 data = va_arg(args, void *);
732 attrs = g_list_append(attrs, data);
734 purple_status_set_active_with_attrs_list(status, active, attrs);
735 g_list_free(attrs);
738 void
739 purple_status_set_active_with_attrs_list(PurpleStatus *status, gboolean active,
740 GList *attrs)
742 gboolean changed = FALSE;
743 GList *l;
744 GList *specified_attr_ids = NULL;
745 PurpleStatusType *status_type;
747 g_return_if_fail(status != NULL);
749 if (!active && purple_status_is_exclusive(status))
751 purple_debug_error("status",
752 "Cannot deactivate an exclusive status (%s).\n",
753 purple_status_get_id(status));
754 return;
757 if (status->active != active)
759 changed = TRUE;
762 status->active = active;
764 /* Set any attributes */
765 l = attrs;
766 while (l != NULL)
768 const gchar *id;
769 PurpleValue *value;
771 id = l->data;
772 l = l->next;
773 value = purple_status_get_attr_value(status, id);
774 if (value == NULL)
776 purple_debug_warning("status", "The attribute \"%s\" on the status \"%s\" is "
777 "not supported.\n", id, status->type->name);
778 /* Skip over the data and move on to the next attribute */
779 l = l->next;
780 continue;
783 specified_attr_ids = g_list_prepend(specified_attr_ids, (gpointer)id);
785 if (value->type == PURPLE_TYPE_STRING)
787 const gchar *string_data = l->data;
788 l = l->next;
789 if (purple_strequal(string_data, value->data.string_data))
790 continue;
791 purple_status_set_attr_string(status, id, string_data);
792 changed = TRUE;
794 else if (value->type == PURPLE_TYPE_INT)
796 int int_data = GPOINTER_TO_INT(l->data);
797 l = l->next;
798 if (int_data == value->data.int_data)
799 continue;
800 purple_status_set_attr_int(status, id, int_data);
801 changed = TRUE;
803 else if (value->type == PURPLE_TYPE_BOOLEAN)
805 gboolean boolean_data = GPOINTER_TO_INT(l->data);
806 l = l->next;
807 if (boolean_data == value->data.boolean_data)
808 continue;
809 purple_status_set_attr_boolean(status, id, boolean_data);
810 changed = TRUE;
812 else
814 /* We don't know what the data is--skip over it */
815 l = l->next;
819 /* Reset any unspecified attributes to their default value */
820 status_type = purple_status_get_type(status);
821 l = purple_status_type_get_attrs(status_type);
822 while (l != NULL) {
823 PurpleStatusAttr *attr;
825 attr = l->data;
826 l = l->next;
828 if (!g_list_find_custom(specified_attr_ids, attr->id, (GCompareFunc)strcmp)) {
829 PurpleValue *default_value;
830 default_value = purple_status_attr_get_value(attr);
831 if (default_value->type == PURPLE_TYPE_STRING) {
832 const char *cur = purple_status_get_attr_string(status, attr->id);
833 const char *def = purple_value_get_string(default_value);
834 if ((cur == NULL && def == NULL)
835 || (cur != NULL && def != NULL
836 && !strcmp(cur, def))) {
837 continue;
840 purple_status_set_attr_string(status, attr->id, def);
841 } else if (default_value->type == PURPLE_TYPE_INT) {
842 int cur = purple_status_get_attr_int(status, attr->id);
843 int def = purple_value_get_int(default_value);
844 if (cur == def)
845 continue;
847 purple_status_set_attr_int(status, attr->id, def);
848 } else if (default_value->type == PURPLE_TYPE_BOOLEAN) {
849 gboolean cur = purple_status_get_attr_boolean(status, attr->id);
850 gboolean def = purple_value_get_boolean(default_value);
851 if (cur == def)
852 continue;
854 purple_status_set_attr_boolean(status, attr->id, def);
856 changed = TRUE;
859 g_list_free(specified_attr_ids);
861 if (!changed)
862 return;
863 status_has_changed(status);
866 void
867 purple_status_set_attr_boolean(PurpleStatus *status, const char *id,
868 gboolean value)
870 PurpleValue *attr_value;
872 g_return_if_fail(status != NULL);
873 g_return_if_fail(id != NULL);
875 /* Make sure this attribute exists and is the correct type. */
876 attr_value = purple_status_get_attr_value(status, id);
877 g_return_if_fail(attr_value != NULL);
878 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_BOOLEAN);
880 purple_value_set_boolean(attr_value, value);
883 void
884 purple_status_set_attr_int(PurpleStatus *status, const char *id, int value)
886 PurpleValue *attr_value;
888 g_return_if_fail(status != NULL);
889 g_return_if_fail(id != NULL);
891 /* Make sure this attribute exists and is the correct type. */
892 attr_value = purple_status_get_attr_value(status, id);
893 g_return_if_fail(attr_value != NULL);
894 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_INT);
896 purple_value_set_int(attr_value, value);
899 void
900 purple_status_set_attr_string(PurpleStatus *status, const char *id,
901 const char *value)
903 PurpleValue *attr_value;
905 g_return_if_fail(status != NULL);
906 g_return_if_fail(id != NULL);
908 /* Make sure this attribute exists and is the correct type. */
909 attr_value = purple_status_get_attr_value(status, id);
910 /* This used to be g_return_if_fail, but it's failing a LOT, so
911 * let's generate a log error for now. */
912 /* g_return_if_fail(attr_value != NULL); */
913 if (attr_value == NULL) {
914 purple_debug_error("status",
915 "Attempted to set status attribute '%s' for "
916 "status '%s', which is not legal. Fix "
917 "this!\n", id,
918 purple_status_type_get_name(purple_status_get_type(status)));
919 return;
921 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_STRING);
923 /* XXX: Check if the value has actually changed. If it has, and the status
924 * is active, should this trigger 'status_has_changed'? */
925 purple_value_set_string(attr_value, value);
928 PurpleStatusType *
929 purple_status_get_type(const PurpleStatus *status)
931 g_return_val_if_fail(status != NULL, NULL);
933 return status->type;
936 PurplePresence *
937 purple_status_get_presence(const PurpleStatus *status)
939 g_return_val_if_fail(status != NULL, NULL);
941 return status->presence;
944 const char *
945 purple_status_get_id(const PurpleStatus *status)
947 g_return_val_if_fail(status != NULL, NULL);
949 return purple_status_type_get_id(purple_status_get_type(status));
952 const char *
953 purple_status_get_name(const PurpleStatus *status)
955 g_return_val_if_fail(status != NULL, NULL);
957 return purple_status_type_get_name(purple_status_get_type(status));
960 gboolean
961 purple_status_is_independent(const PurpleStatus *status)
963 g_return_val_if_fail(status != NULL, FALSE);
965 return purple_status_type_is_independent(purple_status_get_type(status));
968 gboolean
969 purple_status_is_exclusive(const PurpleStatus *status)
971 g_return_val_if_fail(status != NULL, FALSE);
973 return purple_status_type_is_exclusive(purple_status_get_type(status));
976 gboolean
977 purple_status_is_available(const PurpleStatus *status)
979 g_return_val_if_fail(status != NULL, FALSE);
981 return purple_status_type_is_available(purple_status_get_type(status));
984 gboolean
985 purple_status_is_active(const PurpleStatus *status)
987 g_return_val_if_fail(status != NULL, FALSE);
989 return status->active;
992 gboolean
993 purple_status_is_online(const PurpleStatus *status)
995 PurpleStatusPrimitive primitive;
997 g_return_val_if_fail( status != NULL, FALSE);
999 primitive = purple_status_type_get_primitive(purple_status_get_type(status));
1001 return (primitive != PURPLE_STATUS_UNSET &&
1002 primitive != PURPLE_STATUS_OFFLINE);
1005 PurpleValue *
1006 purple_status_get_attr_value(const PurpleStatus *status, const char *id)
1008 g_return_val_if_fail(status != NULL, NULL);
1009 g_return_val_if_fail(id != NULL, NULL);
1011 return (PurpleValue *)g_hash_table_lookup(status->attr_values, id);
1014 gboolean
1015 purple_status_get_attr_boolean(const PurpleStatus *status, const char *id)
1017 const PurpleValue *value;
1019 g_return_val_if_fail(status != NULL, FALSE);
1020 g_return_val_if_fail(id != NULL, FALSE);
1022 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1023 return FALSE;
1025 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_BOOLEAN, FALSE);
1027 return purple_value_get_boolean(value);
1031 purple_status_get_attr_int(const PurpleStatus *status, const char *id)
1033 const PurpleValue *value;
1035 g_return_val_if_fail(status != NULL, 0);
1036 g_return_val_if_fail(id != NULL, 0);
1038 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1039 return 0;
1041 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_INT, 0);
1043 return purple_value_get_int(value);
1046 const char *
1047 purple_status_get_attr_string(const PurpleStatus *status, const char *id)
1049 const PurpleValue *value;
1051 g_return_val_if_fail(status != NULL, NULL);
1052 g_return_val_if_fail(id != NULL, NULL);
1054 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1055 return NULL;
1057 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_STRING, NULL);
1059 return purple_value_get_string(value);
1062 gint
1063 purple_status_compare(const PurpleStatus *status1, const PurpleStatus *status2)
1065 PurpleStatusType *type1, *type2;
1066 int score1 = 0, score2 = 0;
1068 if ((status1 == NULL && status2 == NULL) ||
1069 (status1 == status2))
1071 return 0;
1073 else if (status1 == NULL)
1074 return 1;
1075 else if (status2 == NULL)
1076 return -1;
1078 type1 = purple_status_get_type(status1);
1079 type2 = purple_status_get_type(status2);
1081 if (purple_status_is_active(status1))
1082 score1 = primitive_scores[purple_status_type_get_primitive(type1)];
1084 if (purple_status_is_active(status2))
1085 score2 = primitive_scores[purple_status_type_get_primitive(type2)];
1087 if (score1 > score2)
1088 return -1;
1089 else if (score1 < score2)
1090 return 1;
1092 return 0;
1096 /**************************************************************************
1097 * PurplePresence API
1098 **************************************************************************/
1099 PurplePresence *
1100 purple_presence_new(PurplePresenceContext context)
1102 PurplePresence *presence;
1104 g_return_val_if_fail(context != PURPLE_PRESENCE_CONTEXT_UNSET, NULL);
1106 presence = g_new0(PurplePresence, 1);
1107 PURPLE_DBUS_REGISTER_POINTER(presence, PurplePresence);
1109 presence->context = context;
1111 presence->status_table =
1112 g_hash_table_new_full(g_str_hash, g_str_equal,
1113 g_free, NULL);
1115 return presence;
1118 PurplePresence *
1119 purple_presence_new_for_account(PurpleAccount *account)
1121 PurplePresence *presence = NULL;
1122 g_return_val_if_fail(account != NULL, NULL);
1124 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_ACCOUNT);
1125 presence->u.account = account;
1126 presence->statuses = purple_prpl_get_statuses(account, presence);
1128 return presence;
1131 PurplePresence *
1132 purple_presence_new_for_conv(PurpleConversation *conv)
1134 PurplePresence *presence;
1136 g_return_val_if_fail(conv != NULL, NULL);
1138 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_CONV);
1139 presence->u.chat.conv = conv;
1140 /* presence->statuses = purple_prpl_get_statuses(conv->account, presence); ? */
1142 return presence;
1145 PurplePresence *
1146 purple_presence_new_for_buddy(PurpleBuddy *buddy)
1148 PurplePresence *presence;
1149 PurpleAccount *account;
1151 g_return_val_if_fail(buddy != NULL, NULL);
1152 account = purple_buddy_get_account(buddy);
1154 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_BUDDY);
1156 presence->u.buddy.name = g_strdup(purple_buddy_get_name(buddy));
1157 presence->u.buddy.account = account;
1158 presence->statuses = purple_prpl_get_statuses(account, presence);
1160 presence->u.buddy.buddy = buddy;
1162 return presence;
1165 void
1166 purple_presence_destroy(PurplePresence *presence)
1168 g_return_if_fail(presence != NULL);
1170 if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_BUDDY)
1172 g_free(presence->u.buddy.name);
1174 else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_CONV)
1176 g_free(presence->u.chat.user);
1179 g_list_foreach(presence->statuses, (GFunc)purple_status_destroy, NULL);
1180 g_list_free(presence->statuses);
1182 g_hash_table_destroy(presence->status_table);
1184 PURPLE_DBUS_UNREGISTER_POINTER(presence);
1185 g_free(presence);
1188 void
1189 purple_presence_add_status(PurplePresence *presence, PurpleStatus *status)
1191 g_return_if_fail(presence != NULL);
1192 g_return_if_fail(status != NULL);
1194 presence->statuses = g_list_append(presence->statuses, status);
1196 g_hash_table_insert(presence->status_table,
1197 g_strdup(purple_status_get_id(status)), status);
1200 void
1201 purple_presence_add_list(PurplePresence *presence, GList *source_list)
1203 GList *l;
1205 g_return_if_fail(presence != NULL);
1206 g_return_if_fail(source_list != NULL);
1208 for (l = source_list; l != NULL; l = l->next)
1209 purple_presence_add_status(presence, (PurpleStatus *)l->data);
1212 void
1213 purple_presence_set_status_active(PurplePresence *presence, const char *status_id,
1214 gboolean active)
1216 PurpleStatus *status;
1218 g_return_if_fail(presence != NULL);
1219 g_return_if_fail(status_id != NULL);
1221 status = purple_presence_get_status(presence, status_id);
1223 g_return_if_fail(status != NULL);
1224 /* TODO: Should we do the following? */
1225 /* g_return_if_fail(active == status->active); */
1227 if (purple_status_is_exclusive(status))
1229 if (!active)
1231 purple_debug_warning("status",
1232 "Attempted to set a non-independent status "
1233 "(%s) inactive. Only independent statuses "
1234 "can be specifically marked inactive.",
1235 status_id);
1236 return;
1240 purple_status_set_active(status, active);
1243 void
1244 purple_presence_switch_status(PurplePresence *presence, const char *status_id)
1246 purple_presence_set_status_active(presence, status_id, TRUE);
1249 static void
1250 update_buddy_idle(PurpleBuddy *buddy, PurplePresence *presence,
1251 time_t current_time, gboolean old_idle, gboolean idle)
1253 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
1254 PurpleAccount *account = purple_buddy_get_account(buddy);
1256 if (!old_idle && idle)
1258 if (purple_prefs_get_bool("/purple/logging/log_system"))
1260 PurpleLog *log = purple_account_get_log(account, FALSE);
1262 if (log != NULL)
1264 char *tmp, *tmp2;
1265 tmp = g_strdup_printf(_("%s became idle"),
1266 purple_buddy_get_alias(buddy));
1267 tmp2 = g_markup_escape_text(tmp, -1);
1268 g_free(tmp);
1270 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1271 purple_buddy_get_alias(buddy), current_time, tmp2);
1272 g_free(tmp2);
1276 else if (old_idle && !idle)
1278 if (purple_prefs_get_bool("/purple/logging/log_system"))
1280 PurpleLog *log = purple_account_get_log(account, FALSE);
1282 if (log != NULL)
1284 char *tmp, *tmp2;
1285 tmp = g_strdup_printf(_("%s became unidle"),
1286 purple_buddy_get_alias(buddy));
1287 tmp2 = g_markup_escape_text(tmp, -1);
1288 g_free(tmp);
1290 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1291 purple_buddy_get_alias(buddy), current_time, tmp2);
1292 g_free(tmp2);
1297 if (old_idle != idle)
1298 purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
1299 old_idle, idle);
1301 purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
1303 /* Should this be done here? It'd perhaps make more sense to
1304 * connect to buddy-[un]idle signals and update from there
1307 if (ops != NULL && ops->update != NULL)
1308 ops->update(purple_get_blist(), (PurpleBlistNode *)buddy);
1311 void
1312 purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time)
1314 gboolean old_idle;
1315 time_t current_time;
1317 g_return_if_fail(presence != NULL);
1319 if (presence->idle == idle && presence->idle_time == idle_time)
1320 return;
1322 old_idle = presence->idle;
1323 presence->idle = idle;
1324 presence->idle_time = (idle ? idle_time : 0);
1326 current_time = time(NULL);
1328 if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_BUDDY)
1330 update_buddy_idle(purple_presence_get_buddy(presence), presence, current_time,
1331 old_idle, idle);
1333 else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_ACCOUNT)
1335 PurpleAccount *account;
1336 PurpleConnection *gc = NULL;
1337 PurplePlugin *prpl = NULL;
1338 PurplePluginProtocolInfo *prpl_info = NULL;
1340 account = purple_presence_get_account(presence);
1342 if (purple_prefs_get_bool("/purple/logging/log_system"))
1344 PurpleLog *log = purple_account_get_log(account, FALSE);
1346 if (log != NULL)
1348 char *msg, *tmp;
1350 if (idle)
1351 tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
1352 else
1353 tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
1355 msg = g_markup_escape_text(tmp, -1);
1356 g_free(tmp);
1357 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1358 purple_account_get_username(account),
1359 (idle ? idle_time : current_time), msg);
1360 g_free(msg);
1364 gc = purple_account_get_connection(account);
1366 if(gc)
1367 prpl = purple_connection_get_prpl(gc);
1369 if(PURPLE_CONNECTION_IS_CONNECTED(gc) && prpl != NULL)
1370 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
1372 if (prpl_info && prpl_info->set_idle)
1373 prpl_info->set_idle(gc, (idle ? (current_time - idle_time) : 0));
1377 void
1378 purple_presence_set_login_time(PurplePresence *presence, time_t login_time)
1380 g_return_if_fail(presence != NULL);
1382 if (presence->login_time == login_time)
1383 return;
1385 presence->login_time = login_time;
1388 PurplePresenceContext
1389 purple_presence_get_context(const PurplePresence *presence)
1391 g_return_val_if_fail(presence != NULL, PURPLE_PRESENCE_CONTEXT_UNSET);
1393 return presence->context;
1396 PurpleAccount *
1397 purple_presence_get_account(const PurplePresence *presence)
1399 PurplePresenceContext context;
1401 g_return_val_if_fail(presence != NULL, NULL);
1403 context = purple_presence_get_context(presence);
1405 g_return_val_if_fail(context == PURPLE_PRESENCE_CONTEXT_ACCOUNT ||
1406 context == PURPLE_PRESENCE_CONTEXT_BUDDY, NULL);
1408 return presence->u.account;
1411 PurpleConversation *
1412 purple_presence_get_conversation(const PurplePresence *presence)
1414 g_return_val_if_fail(presence != NULL, NULL);
1415 g_return_val_if_fail(purple_presence_get_context(presence) ==
1416 PURPLE_PRESENCE_CONTEXT_CONV, NULL);
1418 return presence->u.chat.conv;
1421 const char *
1422 purple_presence_get_chat_user(const PurplePresence *presence)
1424 g_return_val_if_fail(presence != NULL, NULL);
1425 g_return_val_if_fail(purple_presence_get_context(presence) ==
1426 PURPLE_PRESENCE_CONTEXT_CONV, NULL);
1428 return presence->u.chat.user;
1431 PurpleBuddy *
1432 purple_presence_get_buddy(const PurplePresence *presence)
1434 g_return_val_if_fail(presence != NULL, NULL);
1435 g_return_val_if_fail(purple_presence_get_context(presence) ==
1436 PURPLE_PRESENCE_CONTEXT_BUDDY, NULL);
1438 return presence->u.buddy.buddy;
1441 GList *
1442 purple_presence_get_statuses(const PurplePresence *presence)
1444 g_return_val_if_fail(presence != NULL, NULL);
1446 return presence->statuses;
1449 PurpleStatus *
1450 purple_presence_get_status(const PurplePresence *presence, const char *status_id)
1452 PurpleStatus *status;
1453 GList *l = NULL;
1455 g_return_val_if_fail(presence != NULL, NULL);
1456 g_return_val_if_fail(status_id != NULL, NULL);
1458 /* What's the purpose of this hash table? */
1459 status = (PurpleStatus *)g_hash_table_lookup(presence->status_table,
1460 status_id);
1462 if (status == NULL) {
1463 for (l = purple_presence_get_statuses(presence);
1464 l != NULL && status == NULL; l = l->next)
1466 PurpleStatus *temp_status = l->data;
1468 if (purple_strequal(status_id, purple_status_get_id(temp_status)))
1469 status = temp_status;
1472 if (status != NULL)
1473 g_hash_table_insert(presence->status_table,
1474 g_strdup(purple_status_get_id(status)), status);
1477 return status;
1480 PurpleStatus *
1481 purple_presence_get_active_status(const PurplePresence *presence)
1483 g_return_val_if_fail(presence != NULL, NULL);
1485 return presence->active_status;
1488 gboolean
1489 purple_presence_is_available(const PurplePresence *presence)
1491 PurpleStatus *status;
1493 g_return_val_if_fail(presence != NULL, FALSE);
1495 status = purple_presence_get_active_status(presence);
1497 return ((status != NULL && purple_status_is_available(status)) &&
1498 !purple_presence_is_idle(presence));
1501 gboolean
1502 purple_presence_is_online(const PurplePresence *presence)
1504 PurpleStatus *status;
1506 g_return_val_if_fail(presence != NULL, FALSE);
1508 if ((status = purple_presence_get_active_status(presence)) == NULL)
1509 return FALSE;
1511 return purple_status_is_online(status);
1514 gboolean
1515 purple_presence_is_status_active(const PurplePresence *presence,
1516 const char *status_id)
1518 PurpleStatus *status;
1520 g_return_val_if_fail(presence != NULL, FALSE);
1521 g_return_val_if_fail(status_id != NULL, FALSE);
1523 status = purple_presence_get_status(presence, status_id);
1525 return (status != NULL && purple_status_is_active(status));
1528 gboolean
1529 purple_presence_is_status_primitive_active(const PurplePresence *presence,
1530 PurpleStatusPrimitive primitive)
1532 GList *l;
1534 g_return_val_if_fail(presence != NULL, FALSE);
1535 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, FALSE);
1537 for (l = purple_presence_get_statuses(presence);
1538 l != NULL; l = l->next)
1540 PurpleStatus *temp_status = l->data;
1541 PurpleStatusType *type = purple_status_get_type(temp_status);
1543 if (purple_status_type_get_primitive(type) == primitive &&
1544 purple_status_is_active(temp_status))
1545 return TRUE;
1547 return FALSE;
1550 gboolean
1551 purple_presence_is_idle(const PurplePresence *presence)
1553 g_return_val_if_fail(presence != NULL, FALSE);
1555 return purple_presence_is_online(presence) && presence->idle;
1558 time_t
1559 purple_presence_get_idle_time(const PurplePresence *presence)
1561 g_return_val_if_fail(presence != NULL, 0);
1563 return presence->idle_time;
1566 time_t
1567 purple_presence_get_login_time(const PurplePresence *presence)
1569 g_return_val_if_fail(presence != NULL, 0);
1571 return purple_presence_is_online(presence) ? presence->login_time : 0;
1574 static int
1575 purple_presence_compute_score(const PurplePresence *presence)
1577 GList *l;
1578 int score = 0;
1580 for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) {
1581 PurpleStatus *status = (PurpleStatus *)l->data;
1582 PurpleStatusType *type = purple_status_get_type(status);
1584 if (purple_status_is_active(status)) {
1585 score += primitive_scores[purple_status_type_get_primitive(type)];
1586 if (!purple_status_is_online(status)) {
1587 PurpleBuddy *b = purple_presence_get_buddy(presence);
1588 if (b && purple_account_supports_offline_message(purple_buddy_get_account(b), b))
1589 score += primitive_scores[SCORE_OFFLINE_MESSAGE];
1593 score += purple_account_get_int(purple_presence_get_account(presence), "score", 0);
1594 if (purple_presence_is_idle(presence))
1595 score += primitive_scores[SCORE_IDLE];
1596 return score;
1599 gint
1600 purple_presence_compare(const PurplePresence *presence1,
1601 const PurplePresence *presence2)
1603 time_t idle_time_1, idle_time_2;
1604 int score1 = 0, score2 = 0;
1606 if (presence1 == presence2)
1607 return 0;
1608 else if (presence1 == NULL)
1609 return 1;
1610 else if (presence2 == NULL)
1611 return -1;
1613 if (purple_presence_is_online(presence1) &&
1614 !purple_presence_is_online(presence2))
1615 return -1;
1616 else if (purple_presence_is_online(presence2) &&
1617 !purple_presence_is_online(presence1))
1618 return 1;
1620 /* Compute the score of the first set of statuses. */
1621 score1 = purple_presence_compute_score(presence1);
1623 /* Compute the score of the second set of statuses. */
1624 score2 = purple_presence_compute_score(presence2);
1626 idle_time_1 = time(NULL) - purple_presence_get_idle_time(presence1);
1627 idle_time_2 = time(NULL) - purple_presence_get_idle_time(presence2);
1629 if (idle_time_1 > idle_time_2)
1630 score1 += primitive_scores[SCORE_IDLE_TIME];
1631 else if (idle_time_1 < idle_time_2)
1632 score2 += primitive_scores[SCORE_IDLE_TIME];
1634 if (score1 < score2)
1635 return 1;
1636 else if (score1 > score2)
1637 return -1;
1639 return 0;
1643 /**************************************************************************
1644 * Status subsystem
1645 **************************************************************************/
1646 static void
1647 score_pref_changed_cb(const char *name, PurplePrefType type,
1648 gconstpointer value, gpointer data)
1650 int index = GPOINTER_TO_INT(data);
1652 primitive_scores[index] = GPOINTER_TO_INT(value);
1655 void *
1656 purple_status_get_handle(void) {
1657 static int handle;
1659 return &handle;
1662 void
1663 purple_status_init(void)
1665 void *handle = purple_status_get_handle();
1667 purple_prefs_add_none("/purple/status");
1668 purple_prefs_add_none("/purple/status/scores");
1670 purple_prefs_add_int("/purple/status/scores/offline",
1671 primitive_scores[PURPLE_STATUS_OFFLINE]);
1672 purple_prefs_add_int("/purple/status/scores/available",
1673 primitive_scores[PURPLE_STATUS_AVAILABLE]);
1674 purple_prefs_add_int("/purple/status/scores/invisible",
1675 primitive_scores[PURPLE_STATUS_INVISIBLE]);
1676 purple_prefs_add_int("/purple/status/scores/away",
1677 primitive_scores[PURPLE_STATUS_AWAY]);
1678 purple_prefs_add_int("/purple/status/scores/extended_away",
1679 primitive_scores[PURPLE_STATUS_EXTENDED_AWAY]);
1680 purple_prefs_add_int("/purple/status/scores/idle",
1681 primitive_scores[SCORE_IDLE]);
1682 purple_prefs_add_int("/purple/status/scores/offline_msg",
1683 primitive_scores[SCORE_OFFLINE_MESSAGE]);
1685 purple_prefs_connect_callback(handle, "/purple/status/scores/offline",
1686 score_pref_changed_cb,
1687 GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
1688 purple_prefs_connect_callback(handle, "/purple/status/scores/available",
1689 score_pref_changed_cb,
1690 GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
1691 purple_prefs_connect_callback(handle, "/purple/status/scores/invisible",
1692 score_pref_changed_cb,
1693 GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
1694 purple_prefs_connect_callback(handle, "/purple/status/scores/away",
1695 score_pref_changed_cb,
1696 GINT_TO_POINTER(PURPLE_STATUS_AWAY));
1697 purple_prefs_connect_callback(handle, "/purple/status/scores/extended_away",
1698 score_pref_changed_cb,
1699 GINT_TO_POINTER(PURPLE_STATUS_EXTENDED_AWAY));
1700 purple_prefs_connect_callback(handle, "/purple/status/scores/idle",
1701 score_pref_changed_cb,
1702 GINT_TO_POINTER(SCORE_IDLE));
1703 purple_prefs_connect_callback(handle, "/purple/status/scores/offline_msg",
1704 score_pref_changed_cb,
1705 GINT_TO_POINTER(SCORE_OFFLINE_MESSAGE));
1707 purple_prefs_trigger_callback("/purple/status/scores/offline");
1708 purple_prefs_trigger_callback("/purple/status/scores/available");
1709 purple_prefs_trigger_callback("/purple/status/scores/invisible");
1710 purple_prefs_trigger_callback("/purple/status/scores/away");
1711 purple_prefs_trigger_callback("/purple/status/scores/extended_away");
1712 purple_prefs_trigger_callback("/purple/status/scores/idle");
1713 purple_prefs_trigger_callback("/purple/status/scores/offline_msg");
1716 void
1717 purple_status_uninit(void)
1719 purple_prefs_disconnect_by_handle(purple_prefs_get_handle());