Move the "Change status to" menu to be beside the checkbox controlling it.
[pidgin-git.git] / libpurple / status.c
blob2040db1aff1d7598bcc8a0ab7fa26ffae4dda9c8
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 -10, /* idle, special case. */
141 -5, /* idle time, special case. */
142 10 /* Offline messageable */
145 #define SCORE_IDLE 9
146 #define SCORE_IDLE_TIME 10
147 #define SCORE_OFFLINE_MESSAGE 11
149 /**************************************************************************
150 * PurpleStatusPrimitive API
151 **************************************************************************/
152 static struct PurpleStatusPrimitiveMap
154 PurpleStatusPrimitive type;
155 const char *id;
156 const char *name;
158 } const status_primitive_map[] =
160 { PURPLE_STATUS_UNSET, "unset", N_("Unset") },
161 { PURPLE_STATUS_OFFLINE, "offline", N_("Offline") },
162 { PURPLE_STATUS_AVAILABLE, "available", N_("Available") },
163 { PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") },
164 { PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") },
165 { PURPLE_STATUS_AWAY, "away", N_("Away") },
166 { PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") },
167 { PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") },
168 { PURPLE_STATUS_TUNE, "tune", N_("Listening to music") }
171 const char *
172 purple_primitive_get_id_from_type(PurpleStatusPrimitive type)
174 int i;
176 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
178 if (type == status_primitive_map[i].type)
179 return status_primitive_map[i].id;
182 return status_primitive_map[0].id;
185 const char *
186 purple_primitive_get_name_from_type(PurpleStatusPrimitive type)
188 int i;
190 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
192 if (type == status_primitive_map[i].type)
193 return _(status_primitive_map[i].name);
196 return _(status_primitive_map[0].name);
199 PurpleStatusPrimitive
200 purple_primitive_get_type_from_id(const char *id)
202 int i;
204 g_return_val_if_fail(id != NULL, PURPLE_STATUS_UNSET);
206 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
208 if (purple_strequal(id, status_primitive_map[i].id))
209 return status_primitive_map[i].type;
212 return status_primitive_map[0].type;
216 /**************************************************************************
217 * PurpleStatusType API
218 **************************************************************************/
219 PurpleStatusType *
220 purple_status_type_new_full(PurpleStatusPrimitive primitive, const char *id,
221 const char *name, gboolean saveable,
222 gboolean user_settable, gboolean independent)
224 PurpleStatusType *status_type;
226 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
228 status_type = g_new0(PurpleStatusType, 1);
229 PURPLE_DBUS_REGISTER_POINTER(status_type, PurpleStatusType);
231 status_type->primitive = primitive;
232 status_type->saveable = saveable;
233 status_type->user_settable = user_settable;
234 status_type->independent = independent;
236 if (id != NULL)
237 status_type->id = g_strdup(id);
238 else
239 status_type->id = g_strdup(purple_primitive_get_id_from_type(primitive));
241 if (name != NULL)
242 status_type->name = g_strdup(name);
243 else
244 status_type->name = g_strdup(purple_primitive_get_name_from_type(primitive));
246 return status_type;
249 PurpleStatusType *
250 purple_status_type_new(PurpleStatusPrimitive primitive, const char *id,
251 const char *name, gboolean user_settable)
253 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
255 return purple_status_type_new_full(primitive, id, name, TRUE,
256 user_settable, FALSE);
259 PurpleStatusType *
260 purple_status_type_new_with_attrs(PurpleStatusPrimitive primitive,
261 const char *id, const char *name,
262 gboolean saveable, gboolean user_settable,
263 gboolean independent, const char *attr_id,
264 const char *attr_name, PurpleValue *attr_value,
265 ...)
267 PurpleStatusType *status_type;
268 va_list args;
270 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
271 g_return_val_if_fail(attr_id != NULL, NULL);
272 g_return_val_if_fail(attr_name != NULL, NULL);
273 g_return_val_if_fail(attr_value != NULL, NULL);
275 status_type = purple_status_type_new_full(primitive, id, name, saveable,
276 user_settable, independent);
278 /* Add the first attribute */
279 purple_status_type_add_attr(status_type, attr_id, attr_name, attr_value);
281 va_start(args, attr_value);
282 purple_status_type_add_attrs_vargs(status_type, args);
283 va_end(args);
285 return status_type;
288 void
289 purple_status_type_destroy(PurpleStatusType *status_type)
291 g_return_if_fail(status_type != NULL);
293 g_free(status_type->id);
294 g_free(status_type->name);
295 g_free(status_type->primary_attr_id);
297 g_list_foreach(status_type->attrs, (GFunc)purple_status_attr_destroy, NULL);
298 g_list_free(status_type->attrs);
300 PURPLE_DBUS_UNREGISTER_POINTER(status_type);
301 g_free(status_type);
304 void
305 purple_status_type_set_primary_attr(PurpleStatusType *status_type, const char *id)
307 g_return_if_fail(status_type != NULL);
309 g_free(status_type->primary_attr_id);
310 status_type->primary_attr_id = g_strdup(id);
313 void
314 purple_status_type_add_attr(PurpleStatusType *status_type, const char *id,
315 const char *name, PurpleValue *value)
317 PurpleStatusAttr *attr;
319 g_return_if_fail(status_type != NULL);
320 g_return_if_fail(id != NULL);
321 g_return_if_fail(name != NULL);
322 g_return_if_fail(value != NULL);
324 attr = purple_status_attr_new(id, name, value);
326 status_type->attrs = g_list_append(status_type->attrs, attr);
329 void
330 purple_status_type_add_attrs_vargs(PurpleStatusType *status_type, va_list args)
332 const char *id, *name;
333 PurpleValue *value;
335 g_return_if_fail(status_type != NULL);
337 while ((id = va_arg(args, const char *)) != NULL)
339 name = va_arg(args, const char *);
340 g_return_if_fail(name != NULL);
342 value = va_arg(args, PurpleValue *);
343 g_return_if_fail(value != NULL);
345 purple_status_type_add_attr(status_type, id, name, value);
349 void
350 purple_status_type_add_attrs(PurpleStatusType *status_type, const char *id,
351 const char *name, PurpleValue *value, ...)
353 va_list args;
355 g_return_if_fail(status_type != NULL);
356 g_return_if_fail(id != NULL);
357 g_return_if_fail(name != NULL);
358 g_return_if_fail(value != NULL);
360 /* Add the first attribute */
361 purple_status_type_add_attr(status_type, id, name, value);
363 va_start(args, value);
364 purple_status_type_add_attrs_vargs(status_type, args);
365 va_end(args);
368 PurpleStatusPrimitive
369 purple_status_type_get_primitive(const PurpleStatusType *status_type)
371 g_return_val_if_fail(status_type != NULL, PURPLE_STATUS_UNSET);
373 return status_type->primitive;
376 const char *
377 purple_status_type_get_id(const PurpleStatusType *status_type)
379 g_return_val_if_fail(status_type != NULL, NULL);
381 return status_type->id;
384 const char *
385 purple_status_type_get_name(const PurpleStatusType *status_type)
387 g_return_val_if_fail(status_type != NULL, NULL);
389 return status_type->name;
392 gboolean
393 purple_status_type_is_saveable(const PurpleStatusType *status_type)
395 g_return_val_if_fail(status_type != NULL, FALSE);
397 return status_type->saveable;
400 gboolean
401 purple_status_type_is_user_settable(const PurpleStatusType *status_type)
403 g_return_val_if_fail(status_type != NULL, FALSE);
405 return status_type->user_settable;
408 gboolean
409 purple_status_type_is_independent(const PurpleStatusType *status_type)
411 g_return_val_if_fail(status_type != NULL, FALSE);
413 return status_type->independent;
416 gboolean
417 purple_status_type_is_exclusive(const PurpleStatusType *status_type)
419 g_return_val_if_fail(status_type != NULL, FALSE);
421 return !status_type->independent;
424 gboolean
425 purple_status_type_is_available(const PurpleStatusType *status_type)
427 PurpleStatusPrimitive primitive;
429 g_return_val_if_fail(status_type != NULL, FALSE);
431 primitive = purple_status_type_get_primitive(status_type);
433 return (primitive == PURPLE_STATUS_AVAILABLE);
436 const char *
437 purple_status_type_get_primary_attr(const PurpleStatusType *status_type)
439 g_return_val_if_fail(status_type != NULL, NULL);
441 return status_type->primary_attr_id;
444 PurpleStatusAttr *
445 purple_status_type_get_attr(const PurpleStatusType *status_type, const char *id)
447 GList *l;
449 g_return_val_if_fail(status_type != NULL, NULL);
450 g_return_val_if_fail(id != NULL, NULL);
452 for (l = status_type->attrs; l != NULL; l = l->next)
454 PurpleStatusAttr *attr = (PurpleStatusAttr *)l->data;
456 if (purple_strequal(purple_status_attr_get_id(attr), id))
457 return attr;
460 return NULL;
463 GList *
464 purple_status_type_get_attrs(const PurpleStatusType *status_type)
466 g_return_val_if_fail(status_type != NULL, NULL);
468 return status_type->attrs;
471 const PurpleStatusType *
472 purple_status_type_find_with_id(GList *status_types, const char *id)
474 PurpleStatusType *status_type;
476 g_return_val_if_fail(id != NULL, NULL);
478 while (status_types != NULL)
480 status_type = status_types->data;
482 if (purple_strequal(id, status_type->id))
483 return status_type;
485 status_types = status_types->next;
488 return NULL;
492 /**************************************************************************
493 * PurpleStatusAttr API
494 **************************************************************************/
495 PurpleStatusAttr *
496 purple_status_attr_new(const char *id, const char *name, PurpleValue *value_type)
498 PurpleStatusAttr *attr;
500 g_return_val_if_fail(id != NULL, NULL);
501 g_return_val_if_fail(name != NULL, NULL);
502 g_return_val_if_fail(value_type != NULL, NULL);
504 attr = g_new0(PurpleStatusAttr, 1);
505 PURPLE_DBUS_REGISTER_POINTER(attr, PurpleStatusAttr);
507 attr->id = g_strdup(id);
508 attr->name = g_strdup(name);
509 attr->value_type = value_type;
511 return attr;
514 void
515 purple_status_attr_destroy(PurpleStatusAttr *attr)
517 g_return_if_fail(attr != NULL);
519 g_free(attr->id);
520 g_free(attr->name);
522 purple_value_destroy(attr->value_type);
524 PURPLE_DBUS_UNREGISTER_POINTER(attr);
525 g_free(attr);
528 const char *
529 purple_status_attr_get_id(const PurpleStatusAttr *attr)
531 g_return_val_if_fail(attr != NULL, NULL);
533 return attr->id;
536 const char *
537 purple_status_attr_get_name(const PurpleStatusAttr *attr)
539 g_return_val_if_fail(attr != NULL, NULL);
541 return attr->name;
544 PurpleValue *
545 purple_status_attr_get_value(const PurpleStatusAttr *attr)
547 g_return_val_if_fail(attr != NULL, NULL);
549 return attr->value_type;
553 /**************************************************************************
554 * PurpleStatus API
555 **************************************************************************/
556 PurpleStatus *
557 purple_status_new(PurpleStatusType *status_type, PurplePresence *presence)
559 PurpleStatus *status;
560 GList *l;
562 g_return_val_if_fail(status_type != NULL, NULL);
563 g_return_val_if_fail(presence != NULL, NULL);
565 status = g_new0(PurpleStatus, 1);
566 PURPLE_DBUS_REGISTER_POINTER(status, PurpleStatus);
568 status->type = status_type;
569 status->presence = presence;
571 status->attr_values =
572 g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
573 (GDestroyNotify)purple_value_destroy);
575 for (l = purple_status_type_get_attrs(status_type); l != NULL; l = l->next)
577 PurpleStatusAttr *attr = (PurpleStatusAttr *)l->data;
578 PurpleValue *value = purple_status_attr_get_value(attr);
579 PurpleValue *new_value = purple_value_dup(value);
581 g_hash_table_insert(status->attr_values,
582 (char *)purple_status_attr_get_id(attr),
583 new_value);
586 return status;
590 * TODO: If the PurpleStatus is in a PurplePresence, then
591 * remove it from the PurplePresence?
593 void
594 purple_status_destroy(PurpleStatus *status)
596 g_return_if_fail(status != NULL);
598 g_hash_table_destroy(status->attr_values);
600 PURPLE_DBUS_UNREGISTER_POINTER(status);
601 g_free(status);
604 static void
605 notify_buddy_status_update(PurpleBuddy *buddy, PurplePresence *presence,
606 PurpleStatus *old_status, PurpleStatus *new_status)
608 if (purple_prefs_get_bool("/purple/logging/log_system"))
610 time_t current_time = time(NULL);
611 const char *buddy_alias = purple_buddy_get_alias(buddy);
612 char *tmp, *logtmp;
613 PurpleLog *log;
615 if (old_status != NULL)
617 tmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias,
618 purple_buddy_get_name(buddy),
619 purple_status_get_name(old_status),
620 purple_status_get_name(new_status));
621 logtmp = g_markup_escape_text(tmp, -1);
623 else
625 /* old_status == NULL when an independent status is toggled. */
627 if (purple_status_is_active(new_status))
629 tmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias,
630 purple_buddy_get_name(buddy),
631 purple_status_get_name(new_status));
632 logtmp = g_markup_escape_text(tmp, -1);
634 else
636 tmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias,
637 purple_buddy_get_name(buddy),
638 purple_status_get_name(new_status));
639 logtmp = g_markup_escape_text(tmp, -1);
643 log = purple_account_get_log(purple_buddy_get_account(buddy), FALSE);
644 if (log != NULL)
646 purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
647 current_time, logtmp);
650 g_free(tmp);
651 g_free(logtmp);
655 static void
656 notify_status_update(PurplePresence *presence, PurpleStatus *old_status,
657 PurpleStatus *new_status)
659 PurplePresenceContext context = purple_presence_get_context(presence);
661 if (context == PURPLE_PRESENCE_CONTEXT_ACCOUNT)
663 PurpleAccount *account = purple_presence_get_account(presence);
664 PurpleAccountUiOps *ops = purple_accounts_get_ui_ops();
666 if (purple_account_get_enabled(account, purple_core_get_ui()))
667 purple_prpl_change_account_status(account, old_status, new_status);
669 if (ops != NULL && ops->status_changed != NULL)
671 ops->status_changed(account, new_status);
674 else if (context == PURPLE_PRESENCE_CONTEXT_BUDDY)
676 notify_buddy_status_update(purple_presence_get_buddy(presence), presence,
677 old_status, new_status);
681 static void
682 status_has_changed(PurpleStatus *status)
684 PurplePresence *presence;
685 PurpleStatus *old_status;
687 presence = purple_status_get_presence(status);
690 * If this status is exclusive, then we must be setting it to "active."
691 * Since we are setting it to active, we want to set the currently
692 * active status to "inactive."
694 if (purple_status_is_exclusive(status))
696 old_status = purple_presence_get_active_status(presence);
697 if (old_status != NULL && (old_status != status))
698 old_status->active = FALSE;
699 presence->active_status = status;
701 else
702 old_status = NULL;
704 notify_status_update(presence, old_status, status);
707 void
708 purple_status_set_active(PurpleStatus *status, gboolean active)
710 purple_status_set_active_with_attrs_list(status, active, NULL);
714 * This used to parse the va_list directly, but now it creates a GList
715 * and passes it to purple_status_set_active_with_attrs_list(). That
716 * function was created because accounts.c needs to pass a GList of
717 * attributes to the status API.
719 void
720 purple_status_set_active_with_attrs(PurpleStatus *status, gboolean active, va_list args)
722 GList *attrs = NULL;
723 const gchar *id;
724 gpointer data;
726 while ((id = va_arg(args, const char *)) != NULL)
728 attrs = g_list_append(attrs, (char *)id);
729 data = va_arg(args, void *);
730 attrs = g_list_append(attrs, data);
732 purple_status_set_active_with_attrs_list(status, active, attrs);
733 g_list_free(attrs);
736 void
737 purple_status_set_active_with_attrs_list(PurpleStatus *status, gboolean active,
738 GList *attrs)
740 gboolean changed = FALSE;
741 GList *l;
742 GList *specified_attr_ids = NULL;
743 PurpleStatusType *status_type;
745 g_return_if_fail(status != NULL);
747 if (!active && purple_status_is_exclusive(status))
749 purple_debug_error("status",
750 "Cannot deactivate an exclusive status (%s).\n",
751 purple_status_get_id(status));
752 return;
755 if (status->active != active)
757 changed = TRUE;
760 status->active = active;
762 /* Set any attributes */
763 l = attrs;
764 while (l != NULL)
766 const gchar *id;
767 PurpleValue *value;
769 id = l->data;
770 l = l->next;
771 value = purple_status_get_attr_value(status, id);
772 if (value == NULL)
774 purple_debug_warning("status", "The attribute \"%s\" on the status \"%s\" is "
775 "not supported.\n", id, status->type->name);
776 /* Skip over the data and move on to the next attribute */
777 l = l->next;
778 continue;
781 specified_attr_ids = g_list_prepend(specified_attr_ids, (gpointer)id);
783 if (value->type == PURPLE_TYPE_STRING)
785 const gchar *string_data = l->data;
786 l = l->next;
787 if (purple_strequal(string_data, value->data.string_data))
788 continue;
789 purple_status_set_attr_string(status, id, string_data);
790 changed = TRUE;
792 else if (value->type == PURPLE_TYPE_INT)
794 int int_data = GPOINTER_TO_INT(l->data);
795 l = l->next;
796 if (int_data == value->data.int_data)
797 continue;
798 purple_status_set_attr_int(status, id, int_data);
799 changed = TRUE;
801 else if (value->type == PURPLE_TYPE_BOOLEAN)
803 gboolean boolean_data = GPOINTER_TO_INT(l->data);
804 l = l->next;
805 if (boolean_data == value->data.boolean_data)
806 continue;
807 purple_status_set_attr_boolean(status, id, boolean_data);
808 changed = TRUE;
810 else
812 /* We don't know what the data is--skip over it */
813 l = l->next;
817 /* Reset any unspecified attributes to their default value */
818 status_type = purple_status_get_type(status);
819 l = purple_status_type_get_attrs(status_type);
820 while (l != NULL) {
821 PurpleStatusAttr *attr;
823 attr = l->data;
824 l = l->next;
826 if (!g_list_find_custom(specified_attr_ids, attr->id, (GCompareFunc)strcmp)) {
827 PurpleValue *default_value;
828 default_value = purple_status_attr_get_value(attr);
829 if (default_value->type == PURPLE_TYPE_STRING) {
830 const char *cur = purple_status_get_attr_string(status, attr->id);
831 const char *def = purple_value_get_string(default_value);
832 if ((cur == NULL && def == NULL)
833 || (cur != NULL && def != NULL
834 && !strcmp(cur, def))) {
835 continue;
838 purple_status_set_attr_string(status, attr->id, def);
839 } else if (default_value->type == PURPLE_TYPE_INT) {
840 int cur = purple_status_get_attr_int(status, attr->id);
841 int def = purple_value_get_int(default_value);
842 if (cur == def)
843 continue;
845 purple_status_set_attr_int(status, attr->id, def);
846 } else if (default_value->type == PURPLE_TYPE_BOOLEAN) {
847 gboolean cur = purple_status_get_attr_boolean(status, attr->id);
848 gboolean def = purple_value_get_boolean(default_value);
849 if (cur == def)
850 continue;
852 purple_status_set_attr_boolean(status, attr->id, def);
854 changed = TRUE;
857 g_list_free(specified_attr_ids);
859 if (!changed)
860 return;
861 status_has_changed(status);
864 void
865 purple_status_set_attr_boolean(PurpleStatus *status, const char *id,
866 gboolean value)
868 PurpleValue *attr_value;
870 g_return_if_fail(status != NULL);
871 g_return_if_fail(id != NULL);
873 /* Make sure this attribute exists and is the correct type. */
874 attr_value = purple_status_get_attr_value(status, id);
875 g_return_if_fail(attr_value != NULL);
876 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_BOOLEAN);
878 purple_value_set_boolean(attr_value, value);
881 void
882 purple_status_set_attr_int(PurpleStatus *status, const char *id, int value)
884 PurpleValue *attr_value;
886 g_return_if_fail(status != NULL);
887 g_return_if_fail(id != NULL);
889 /* Make sure this attribute exists and is the correct type. */
890 attr_value = purple_status_get_attr_value(status, id);
891 g_return_if_fail(attr_value != NULL);
892 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_INT);
894 purple_value_set_int(attr_value, value);
897 void
898 purple_status_set_attr_string(PurpleStatus *status, const char *id,
899 const char *value)
901 PurpleValue *attr_value;
903 g_return_if_fail(status != NULL);
904 g_return_if_fail(id != NULL);
906 /* Make sure this attribute exists and is the correct type. */
907 attr_value = purple_status_get_attr_value(status, id);
908 /* This used to be g_return_if_fail, but it's failing a LOT, so
909 * let's generate a log error for now. */
910 /* g_return_if_fail(attr_value != NULL); */
911 if (attr_value == NULL) {
912 purple_debug_error("status",
913 "Attempted to set status attribute '%s' for "
914 "status '%s', which is not legal. Fix "
915 "this!\n", id,
916 purple_status_type_get_name(purple_status_get_type(status)));
917 return;
919 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_STRING);
921 /* XXX: Check if the value has actually changed. If it has, and the status
922 * is active, should this trigger 'status_has_changed'? */
923 purple_value_set_string(attr_value, value);
926 PurpleStatusType *
927 purple_status_get_type(const PurpleStatus *status)
929 g_return_val_if_fail(status != NULL, NULL);
931 return status->type;
934 PurplePresence *
935 purple_status_get_presence(const PurpleStatus *status)
937 g_return_val_if_fail(status != NULL, NULL);
939 return status->presence;
942 const char *
943 purple_status_get_id(const PurpleStatus *status)
945 g_return_val_if_fail(status != NULL, NULL);
947 return purple_status_type_get_id(purple_status_get_type(status));
950 const char *
951 purple_status_get_name(const PurpleStatus *status)
953 g_return_val_if_fail(status != NULL, NULL);
955 return purple_status_type_get_name(purple_status_get_type(status));
958 gboolean
959 purple_status_is_independent(const PurpleStatus *status)
961 g_return_val_if_fail(status != NULL, FALSE);
963 return purple_status_type_is_independent(purple_status_get_type(status));
966 gboolean
967 purple_status_is_exclusive(const PurpleStatus *status)
969 g_return_val_if_fail(status != NULL, FALSE);
971 return purple_status_type_is_exclusive(purple_status_get_type(status));
974 gboolean
975 purple_status_is_available(const PurpleStatus *status)
977 g_return_val_if_fail(status != NULL, FALSE);
979 return purple_status_type_is_available(purple_status_get_type(status));
982 gboolean
983 purple_status_is_active(const PurpleStatus *status)
985 g_return_val_if_fail(status != NULL, FALSE);
987 return status->active;
990 gboolean
991 purple_status_is_online(const PurpleStatus *status)
993 PurpleStatusPrimitive primitive;
995 g_return_val_if_fail( status != NULL, FALSE);
997 primitive = purple_status_type_get_primitive(purple_status_get_type(status));
999 return (primitive != PURPLE_STATUS_UNSET &&
1000 primitive != PURPLE_STATUS_OFFLINE);
1003 PurpleValue *
1004 purple_status_get_attr_value(const PurpleStatus *status, const char *id)
1006 g_return_val_if_fail(status != NULL, NULL);
1007 g_return_val_if_fail(id != NULL, NULL);
1009 return (PurpleValue *)g_hash_table_lookup(status->attr_values, id);
1012 gboolean
1013 purple_status_get_attr_boolean(const PurpleStatus *status, const char *id)
1015 const PurpleValue *value;
1017 g_return_val_if_fail(status != NULL, FALSE);
1018 g_return_val_if_fail(id != NULL, FALSE);
1020 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1021 return FALSE;
1023 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_BOOLEAN, FALSE);
1025 return purple_value_get_boolean(value);
1029 purple_status_get_attr_int(const PurpleStatus *status, const char *id)
1031 const PurpleValue *value;
1033 g_return_val_if_fail(status != NULL, 0);
1034 g_return_val_if_fail(id != NULL, 0);
1036 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1037 return 0;
1039 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_INT, 0);
1041 return purple_value_get_int(value);
1044 const char *
1045 purple_status_get_attr_string(const PurpleStatus *status, const char *id)
1047 const PurpleValue *value;
1049 g_return_val_if_fail(status != NULL, NULL);
1050 g_return_val_if_fail(id != NULL, NULL);
1052 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1053 return NULL;
1055 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_STRING, NULL);
1057 return purple_value_get_string(value);
1060 gint
1061 purple_status_compare(const PurpleStatus *status1, const PurpleStatus *status2)
1063 PurpleStatusType *type1, *type2;
1064 int score1 = 0, score2 = 0;
1066 if ((status1 == NULL && status2 == NULL) ||
1067 (status1 == status2))
1069 return 0;
1071 else if (status1 == NULL)
1072 return 1;
1073 else if (status2 == NULL)
1074 return -1;
1076 type1 = purple_status_get_type(status1);
1077 type2 = purple_status_get_type(status2);
1079 if (purple_status_is_active(status1))
1080 score1 = primitive_scores[purple_status_type_get_primitive(type1)];
1082 if (purple_status_is_active(status2))
1083 score2 = primitive_scores[purple_status_type_get_primitive(type2)];
1085 if (score1 > score2)
1086 return -1;
1087 else if (score1 < score2)
1088 return 1;
1090 return 0;
1094 /**************************************************************************
1095 * PurplePresence API
1096 **************************************************************************/
1097 PurplePresence *
1098 purple_presence_new(PurplePresenceContext context)
1100 PurplePresence *presence;
1102 g_return_val_if_fail(context != PURPLE_PRESENCE_CONTEXT_UNSET, NULL);
1104 presence = g_new0(PurplePresence, 1);
1105 PURPLE_DBUS_REGISTER_POINTER(presence, PurplePresence);
1107 presence->context = context;
1109 presence->status_table =
1110 g_hash_table_new_full(g_str_hash, g_str_equal,
1111 g_free, NULL);
1113 return presence;
1116 PurplePresence *
1117 purple_presence_new_for_account(PurpleAccount *account)
1119 PurplePresence *presence = NULL;
1120 g_return_val_if_fail(account != NULL, NULL);
1122 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_ACCOUNT);
1123 presence->u.account = account;
1124 presence->statuses = purple_prpl_get_statuses(account, presence);
1126 return presence;
1129 PurplePresence *
1130 purple_presence_new_for_conv(PurpleConversation *conv)
1132 PurplePresence *presence;
1134 g_return_val_if_fail(conv != NULL, NULL);
1136 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_CONV);
1137 presence->u.chat.conv = conv;
1138 /* presence->statuses = purple_prpl_get_statuses(conv->account, presence); ? */
1140 return presence;
1143 PurplePresence *
1144 purple_presence_new_for_buddy(PurpleBuddy *buddy)
1146 PurplePresence *presence;
1147 PurpleAccount *account;
1149 g_return_val_if_fail(buddy != NULL, NULL);
1150 account = purple_buddy_get_account(buddy);
1152 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_BUDDY);
1154 presence->u.buddy.name = g_strdup(purple_buddy_get_name(buddy));
1155 presence->u.buddy.account = account;
1156 presence->statuses = purple_prpl_get_statuses(account, presence);
1158 presence->u.buddy.buddy = buddy;
1160 return presence;
1163 void
1164 purple_presence_destroy(PurplePresence *presence)
1166 g_return_if_fail(presence != NULL);
1168 if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_BUDDY)
1170 g_free(presence->u.buddy.name);
1172 else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_CONV)
1174 g_free(presence->u.chat.user);
1177 g_list_foreach(presence->statuses, (GFunc)purple_status_destroy, NULL);
1178 g_list_free(presence->statuses);
1180 g_hash_table_destroy(presence->status_table);
1182 PURPLE_DBUS_UNREGISTER_POINTER(presence);
1183 g_free(presence);
1186 void
1187 purple_presence_add_status(PurplePresence *presence, PurpleStatus *status)
1189 g_return_if_fail(presence != NULL);
1190 g_return_if_fail(status != NULL);
1192 presence->statuses = g_list_append(presence->statuses, status);
1194 g_hash_table_insert(presence->status_table,
1195 g_strdup(purple_status_get_id(status)), status);
1198 void
1199 purple_presence_add_list(PurplePresence *presence, GList *source_list)
1201 GList *l;
1203 g_return_if_fail(presence != NULL);
1204 g_return_if_fail(source_list != NULL);
1206 for (l = source_list; l != NULL; l = l->next)
1207 purple_presence_add_status(presence, (PurpleStatus *)l->data);
1210 void
1211 purple_presence_set_status_active(PurplePresence *presence, const char *status_id,
1212 gboolean active)
1214 PurpleStatus *status;
1216 g_return_if_fail(presence != NULL);
1217 g_return_if_fail(status_id != NULL);
1219 status = purple_presence_get_status(presence, status_id);
1221 g_return_if_fail(status != NULL);
1222 /* TODO: Should we do the following? */
1223 /* g_return_if_fail(active == status->active); */
1225 if (purple_status_is_exclusive(status))
1227 if (!active)
1229 purple_debug_warning("status",
1230 "Attempted to set a non-independent status "
1231 "(%s) inactive. Only independent statuses "
1232 "can be specifically marked inactive.",
1233 status_id);
1234 return;
1238 purple_status_set_active(status, active);
1241 void
1242 purple_presence_switch_status(PurplePresence *presence, const char *status_id)
1244 purple_presence_set_status_active(presence, status_id, TRUE);
1247 static void
1248 update_buddy_idle(PurpleBuddy *buddy, PurplePresence *presence,
1249 time_t current_time, gboolean old_idle, gboolean idle)
1251 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
1252 PurpleAccount *account = purple_buddy_get_account(buddy);
1254 if (!old_idle && idle)
1256 if (purple_prefs_get_bool("/purple/logging/log_system"))
1258 PurpleLog *log = purple_account_get_log(account, FALSE);
1260 if (log != NULL)
1262 char *tmp, *tmp2;
1263 tmp = g_strdup_printf(_("%s became idle"),
1264 purple_buddy_get_alias(buddy));
1265 tmp2 = g_markup_escape_text(tmp, -1);
1266 g_free(tmp);
1268 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1269 purple_buddy_get_alias(buddy), current_time, tmp2);
1270 g_free(tmp2);
1274 else if (old_idle && !idle)
1276 if (purple_prefs_get_bool("/purple/logging/log_system"))
1278 PurpleLog *log = purple_account_get_log(account, FALSE);
1280 if (log != NULL)
1282 char *tmp, *tmp2;
1283 tmp = g_strdup_printf(_("%s became unidle"),
1284 purple_buddy_get_alias(buddy));
1285 tmp2 = g_markup_escape_text(tmp, -1);
1286 g_free(tmp);
1288 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1289 purple_buddy_get_alias(buddy), current_time, tmp2);
1290 g_free(tmp2);
1295 if (old_idle != idle)
1296 purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
1297 old_idle, idle);
1299 purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
1301 /* Should this be done here? It'd perhaps make more sense to
1302 * connect to buddy-[un]idle signals and update from there
1305 if (ops != NULL && ops->update != NULL)
1306 ops->update(purple_get_blist(), (PurpleBlistNode *)buddy);
1309 void
1310 purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time)
1312 gboolean old_idle;
1313 time_t current_time;
1315 g_return_if_fail(presence != NULL);
1317 if (presence->idle == idle && presence->idle_time == idle_time)
1318 return;
1320 old_idle = presence->idle;
1321 presence->idle = idle;
1322 presence->idle_time = (idle ? idle_time : 0);
1324 current_time = time(NULL);
1326 if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_BUDDY)
1328 update_buddy_idle(purple_presence_get_buddy(presence), presence, current_time,
1329 old_idle, idle);
1331 else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_ACCOUNT)
1333 PurpleAccount *account;
1334 PurpleConnection *gc = NULL;
1335 PurplePlugin *prpl = NULL;
1336 PurplePluginProtocolInfo *prpl_info = NULL;
1338 account = purple_presence_get_account(presence);
1340 if (purple_prefs_get_bool("/purple/logging/log_system"))
1342 PurpleLog *log = purple_account_get_log(account, FALSE);
1344 if (log != NULL)
1346 char *msg, *tmp;
1348 if (idle)
1349 tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
1350 else
1351 tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
1353 msg = g_markup_escape_text(tmp, -1);
1354 g_free(tmp);
1355 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1356 purple_account_get_username(account),
1357 (idle ? idle_time : current_time), msg);
1358 g_free(msg);
1362 gc = purple_account_get_connection(account);
1364 if(gc)
1365 prpl = purple_connection_get_prpl(gc);
1367 if(PURPLE_CONNECTION_IS_CONNECTED(gc) && prpl != NULL)
1368 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
1370 if (prpl_info && prpl_info->set_idle)
1371 prpl_info->set_idle(gc, (idle ? (current_time - idle_time) : 0));
1375 void
1376 purple_presence_set_login_time(PurplePresence *presence, time_t login_time)
1378 g_return_if_fail(presence != NULL);
1380 if (presence->login_time == login_time)
1381 return;
1383 presence->login_time = login_time;
1386 PurplePresenceContext
1387 purple_presence_get_context(const PurplePresence *presence)
1389 g_return_val_if_fail(presence != NULL, PURPLE_PRESENCE_CONTEXT_UNSET);
1391 return presence->context;
1394 PurpleAccount *
1395 purple_presence_get_account(const PurplePresence *presence)
1397 PurplePresenceContext context;
1399 g_return_val_if_fail(presence != NULL, NULL);
1401 context = purple_presence_get_context(presence);
1403 g_return_val_if_fail(context == PURPLE_PRESENCE_CONTEXT_ACCOUNT ||
1404 context == PURPLE_PRESENCE_CONTEXT_BUDDY, NULL);
1406 return presence->u.account;
1409 PurpleConversation *
1410 purple_presence_get_conversation(const PurplePresence *presence)
1412 g_return_val_if_fail(presence != NULL, NULL);
1413 g_return_val_if_fail(purple_presence_get_context(presence) ==
1414 PURPLE_PRESENCE_CONTEXT_CONV, NULL);
1416 return presence->u.chat.conv;
1419 const char *
1420 purple_presence_get_chat_user(const PurplePresence *presence)
1422 g_return_val_if_fail(presence != NULL, NULL);
1423 g_return_val_if_fail(purple_presence_get_context(presence) ==
1424 PURPLE_PRESENCE_CONTEXT_CONV, NULL);
1426 return presence->u.chat.user;
1429 PurpleBuddy *
1430 purple_presence_get_buddy(const PurplePresence *presence)
1432 g_return_val_if_fail(presence != NULL, NULL);
1433 g_return_val_if_fail(purple_presence_get_context(presence) ==
1434 PURPLE_PRESENCE_CONTEXT_BUDDY, NULL);
1436 return presence->u.buddy.buddy;
1439 GList *
1440 purple_presence_get_statuses(const PurplePresence *presence)
1442 g_return_val_if_fail(presence != NULL, NULL);
1444 return presence->statuses;
1447 PurpleStatus *
1448 purple_presence_get_status(const PurplePresence *presence, const char *status_id)
1450 PurpleStatus *status;
1451 GList *l = NULL;
1453 g_return_val_if_fail(presence != NULL, NULL);
1454 g_return_val_if_fail(status_id != NULL, NULL);
1456 /* What's the purpose of this hash table? */
1457 status = (PurpleStatus *)g_hash_table_lookup(presence->status_table,
1458 status_id);
1460 if (status == NULL) {
1461 for (l = purple_presence_get_statuses(presence);
1462 l != NULL && status == NULL; l = l->next)
1464 PurpleStatus *temp_status = l->data;
1466 if (purple_strequal(status_id, purple_status_get_id(temp_status)))
1467 status = temp_status;
1470 if (status != NULL)
1471 g_hash_table_insert(presence->status_table,
1472 g_strdup(purple_status_get_id(status)), status);
1475 return status;
1478 PurpleStatus *
1479 purple_presence_get_active_status(const PurplePresence *presence)
1481 g_return_val_if_fail(presence != NULL, NULL);
1483 return presence->active_status;
1486 gboolean
1487 purple_presence_is_available(const PurplePresence *presence)
1489 PurpleStatus *status;
1491 g_return_val_if_fail(presence != NULL, FALSE);
1493 status = purple_presence_get_active_status(presence);
1495 return ((status != NULL && purple_status_is_available(status)) &&
1496 !purple_presence_is_idle(presence));
1499 gboolean
1500 purple_presence_is_online(const PurplePresence *presence)
1502 PurpleStatus *status;
1504 g_return_val_if_fail(presence != NULL, FALSE);
1506 if ((status = purple_presence_get_active_status(presence)) == NULL)
1507 return FALSE;
1509 return purple_status_is_online(status);
1512 gboolean
1513 purple_presence_is_status_active(const PurplePresence *presence,
1514 const char *status_id)
1516 PurpleStatus *status;
1518 g_return_val_if_fail(presence != NULL, FALSE);
1519 g_return_val_if_fail(status_id != NULL, FALSE);
1521 status = purple_presence_get_status(presence, status_id);
1523 return (status != NULL && purple_status_is_active(status));
1526 gboolean
1527 purple_presence_is_status_primitive_active(const PurplePresence *presence,
1528 PurpleStatusPrimitive primitive)
1530 GList *l;
1532 g_return_val_if_fail(presence != NULL, FALSE);
1533 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, FALSE);
1535 for (l = purple_presence_get_statuses(presence);
1536 l != NULL; l = l->next)
1538 PurpleStatus *temp_status = l->data;
1539 PurpleStatusType *type = purple_status_get_type(temp_status);
1541 if (purple_status_type_get_primitive(type) == primitive &&
1542 purple_status_is_active(temp_status))
1543 return TRUE;
1545 return FALSE;
1548 gboolean
1549 purple_presence_is_idle(const PurplePresence *presence)
1551 g_return_val_if_fail(presence != NULL, FALSE);
1553 return purple_presence_is_online(presence) && presence->idle;
1556 time_t
1557 purple_presence_get_idle_time(const PurplePresence *presence)
1559 g_return_val_if_fail(presence != NULL, 0);
1561 return presence->idle_time;
1564 time_t
1565 purple_presence_get_login_time(const PurplePresence *presence)
1567 g_return_val_if_fail(presence != NULL, 0);
1569 return purple_presence_is_online(presence) ? presence->login_time : 0;
1572 static int
1573 purple_presence_compute_score(const PurplePresence *presence)
1575 GList *l;
1576 int score = 0;
1578 for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) {
1579 PurpleStatus *status = (PurpleStatus *)l->data;
1580 PurpleStatusType *type = purple_status_get_type(status);
1582 if (purple_status_is_active(status)) {
1583 score += primitive_scores[purple_status_type_get_primitive(type)];
1584 if (!purple_status_is_online(status)) {
1585 PurpleBuddy *b = purple_presence_get_buddy(presence);
1586 if (b && purple_account_supports_offline_message(purple_buddy_get_account(b), b))
1587 score += primitive_scores[SCORE_OFFLINE_MESSAGE];
1591 score += purple_account_get_int(purple_presence_get_account(presence), "score", 0);
1592 if (purple_presence_is_idle(presence))
1593 score += primitive_scores[SCORE_IDLE];
1594 return score;
1597 gint
1598 purple_presence_compare(const PurplePresence *presence1,
1599 const PurplePresence *presence2)
1601 time_t idle_time_1, idle_time_2;
1602 int score1 = 0, score2 = 0;
1604 if (presence1 == presence2)
1605 return 0;
1606 else if (presence1 == NULL)
1607 return 1;
1608 else if (presence2 == NULL)
1609 return -1;
1611 if (purple_presence_is_online(presence1) &&
1612 !purple_presence_is_online(presence2))
1613 return -1;
1614 else if (purple_presence_is_online(presence2) &&
1615 !purple_presence_is_online(presence1))
1616 return 1;
1618 /* Compute the score of the first set of statuses. */
1619 score1 = purple_presence_compute_score(presence1);
1621 /* Compute the score of the second set of statuses. */
1622 score2 = purple_presence_compute_score(presence2);
1624 idle_time_1 = time(NULL) - purple_presence_get_idle_time(presence1);
1625 idle_time_2 = time(NULL) - purple_presence_get_idle_time(presence2);
1627 if (idle_time_1 > idle_time_2)
1628 score1 += primitive_scores[SCORE_IDLE_TIME];
1629 else if (idle_time_1 < idle_time_2)
1630 score2 += primitive_scores[SCORE_IDLE_TIME];
1632 if (score1 < score2)
1633 return 1;
1634 else if (score1 > score2)
1635 return -1;
1637 return 0;
1641 /**************************************************************************
1642 * Status subsystem
1643 **************************************************************************/
1644 static void
1645 score_pref_changed_cb(const char *name, PurplePrefType type,
1646 gconstpointer value, gpointer data)
1648 int index = GPOINTER_TO_INT(data);
1650 primitive_scores[index] = GPOINTER_TO_INT(value);
1653 void *
1654 purple_status_get_handle(void) {
1655 static int handle;
1657 return &handle;
1660 void
1661 purple_status_init(void)
1663 void *handle = purple_status_get_handle();
1665 purple_prefs_add_none("/purple/status");
1666 purple_prefs_add_none("/purple/status/scores");
1668 purple_prefs_add_int("/purple/status/scores/offline",
1669 primitive_scores[PURPLE_STATUS_OFFLINE]);
1670 purple_prefs_add_int("/purple/status/scores/available",
1671 primitive_scores[PURPLE_STATUS_AVAILABLE]);
1672 purple_prefs_add_int("/purple/status/scores/invisible",
1673 primitive_scores[PURPLE_STATUS_INVISIBLE]);
1674 purple_prefs_add_int("/purple/status/scores/away",
1675 primitive_scores[PURPLE_STATUS_AWAY]);
1676 purple_prefs_add_int("/purple/status/scores/extended_away",
1677 primitive_scores[PURPLE_STATUS_EXTENDED_AWAY]);
1678 purple_prefs_add_int("/purple/status/scores/idle",
1679 primitive_scores[SCORE_IDLE]);
1680 purple_prefs_add_int("/purple/status/scores/offline_msg",
1681 primitive_scores[SCORE_OFFLINE_MESSAGE]);
1683 purple_prefs_connect_callback(handle, "/purple/status/scores/offline",
1684 score_pref_changed_cb,
1685 GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
1686 purple_prefs_connect_callback(handle, "/purple/status/scores/available",
1687 score_pref_changed_cb,
1688 GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
1689 purple_prefs_connect_callback(handle, "/purple/status/scores/invisible",
1690 score_pref_changed_cb,
1691 GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
1692 purple_prefs_connect_callback(handle, "/purple/status/scores/away",
1693 score_pref_changed_cb,
1694 GINT_TO_POINTER(PURPLE_STATUS_AWAY));
1695 purple_prefs_connect_callback(handle, "/purple/status/scores/extended_away",
1696 score_pref_changed_cb,
1697 GINT_TO_POINTER(PURPLE_STATUS_EXTENDED_AWAY));
1698 purple_prefs_connect_callback(handle, "/purple/status/scores/idle",
1699 score_pref_changed_cb,
1700 GINT_TO_POINTER(SCORE_IDLE));
1701 purple_prefs_connect_callback(handle, "/purple/status/scores/offline_msg",
1702 score_pref_changed_cb,
1703 GINT_TO_POINTER(SCORE_OFFLINE_MESSAGE));
1705 purple_prefs_trigger_callback("/purple/status/scores/offline");
1706 purple_prefs_trigger_callback("/purple/status/scores/available");
1707 purple_prefs_trigger_callback("/purple/status/scores/invisible");
1708 purple_prefs_trigger_callback("/purple/status/scores/away");
1709 purple_prefs_trigger_callback("/purple/status/scores/extended_away");
1710 purple_prefs_trigger_callback("/purple/status/scores/idle");
1711 purple_prefs_trigger_callback("/purple/status/scores/offline_msg");
1714 void
1715 purple_status_uninit(void)
1717 purple_prefs_disconnect_by_handle(purple_prefs_get_handle());