Fix crashes when filenames end up being NULL in some prpls.
[pidgin-git.git] / libpurple / status.c
blob5feb311e7d04dcebebc0bdbfc82a4e79391661c1
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 #include "internal.h"
28 #include "blist.h"
29 #include "core.h"
30 #include "dbus-maybe.h"
31 #include "debug.h"
32 #include "notify.h"
33 #include "prefs.h"
34 #include "status.h"
36 /**
37 * A type of status.
39 struct _PurpleStatusType
41 PurpleStatusPrimitive primitive;
43 char *id;
44 char *name;
45 char *primary_attr_id;
47 gboolean saveable;
48 gboolean user_settable;
49 gboolean independent;
51 GList *attrs;
54 /**
55 * A status attribute.
57 struct _PurpleStatusAttr
59 char *id;
60 char *name;
61 PurpleValue *value_type;
64 /**
65 * A list of statuses.
67 struct _PurplePresence
69 PurplePresenceContext context;
71 gboolean idle;
72 time_t idle_time;
73 time_t login_time;
75 GList *statuses;
76 GHashTable *status_table;
78 PurpleStatus *active_status;
80 union
82 PurpleAccount *account;
84 struct
86 PurpleConversation *conv;
87 char *user;
89 } chat;
91 struct
93 PurpleAccount *account;
94 char *name;
95 PurpleBuddy *buddy;
97 } buddy;
99 } u;
103 * An active status.
105 struct _PurpleStatus
107 PurpleStatusType *type;
108 PurplePresence *presence;
110 gboolean active;
113 * The current values of the attributes for this status. The
114 * key is a string containing the name of the attribute. It is
115 * a borrowed reference from the list of attrs in the
116 * PurpleStatusType. The value is a PurpleValue.
118 GHashTable *attr_values;
121 typedef struct
123 PurpleAccount *account;
124 char *name;
125 } PurpleStatusBuddyKey;
127 static int primitive_scores[] =
129 0, /* unset */
130 -500, /* offline */
131 100, /* available */
132 -75, /* unavailable */
133 -50, /* invisible */
134 -100, /* away */
135 -200, /* extended away */
136 -400, /* mobile */
137 0, /* tune */
138 -10, /* idle, special case. */
139 -5, /* idle time, special case. */
140 10 /* Offline messageable */
143 #define SCORE_IDLE 9
144 #define SCORE_IDLE_TIME 10
145 #define SCORE_OFFLINE_MESSAGE 11
147 /**************************************************************************
148 * PurpleStatusPrimitive API
149 **************************************************************************/
150 static struct PurpleStatusPrimitiveMap
152 PurpleStatusPrimitive type;
153 const char *id;
154 const char *name;
156 } const status_primitive_map[] =
158 { PURPLE_STATUS_UNSET, "unset", N_("Unset") },
159 { PURPLE_STATUS_OFFLINE, "offline", N_("Offline") },
160 { PURPLE_STATUS_AVAILABLE, "available", N_("Available") },
161 { PURPLE_STATUS_UNAVAILABLE, "unavailable", N_("Do not disturb") },
162 { PURPLE_STATUS_INVISIBLE, "invisible", N_("Invisible") },
163 { PURPLE_STATUS_AWAY, "away", N_("Away") },
164 { PURPLE_STATUS_EXTENDED_AWAY, "extended_away", N_("Extended away") },
165 { PURPLE_STATUS_MOBILE, "mobile", N_("Mobile") },
166 { PURPLE_STATUS_TUNE, "tune", N_("Listening to music") }
169 const char *
170 purple_primitive_get_id_from_type(PurpleStatusPrimitive type)
172 int i;
174 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
176 if (type == status_primitive_map[i].type)
177 return status_primitive_map[i].id;
180 return status_primitive_map[0].id;
183 const char *
184 purple_primitive_get_name_from_type(PurpleStatusPrimitive type)
186 int i;
188 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
190 if (type == status_primitive_map[i].type)
191 return _(status_primitive_map[i].name);
194 return _(status_primitive_map[0].name);
197 PurpleStatusPrimitive
198 purple_primitive_get_type_from_id(const char *id)
200 int i;
202 g_return_val_if_fail(id != NULL, PURPLE_STATUS_UNSET);
204 for (i = 0; i < PURPLE_STATUS_NUM_PRIMITIVES; i++)
206 if (!strcmp(id, status_primitive_map[i].id))
207 return status_primitive_map[i].type;
210 return status_primitive_map[0].type;
214 /**************************************************************************
215 * PurpleStatusType API
216 **************************************************************************/
217 PurpleStatusType *
218 purple_status_type_new_full(PurpleStatusPrimitive primitive, const char *id,
219 const char *name, gboolean saveable,
220 gboolean user_settable, gboolean independent)
222 PurpleStatusType *status_type;
224 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
226 status_type = g_new0(PurpleStatusType, 1);
227 PURPLE_DBUS_REGISTER_POINTER(status_type, PurpleStatusType);
229 status_type->primitive = primitive;
230 status_type->saveable = saveable;
231 status_type->user_settable = user_settable;
232 status_type->independent = independent;
234 if (id != NULL)
235 status_type->id = g_strdup(id);
236 else
237 status_type->id = g_strdup(purple_primitive_get_id_from_type(primitive));
239 if (name != NULL)
240 status_type->name = g_strdup(name);
241 else
242 status_type->name = g_strdup(purple_primitive_get_name_from_type(primitive));
244 return status_type;
247 PurpleStatusType *
248 purple_status_type_new(PurpleStatusPrimitive primitive, const char *id,
249 const char *name, gboolean user_settable)
251 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
253 return purple_status_type_new_full(primitive, id, name, TRUE,
254 user_settable, FALSE);
257 PurpleStatusType *
258 purple_status_type_new_with_attrs(PurpleStatusPrimitive primitive,
259 const char *id, const char *name,
260 gboolean saveable, gboolean user_settable,
261 gboolean independent, const char *attr_id,
262 const char *attr_name, PurpleValue *attr_value,
263 ...)
265 PurpleStatusType *status_type;
266 va_list args;
268 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, NULL);
269 g_return_val_if_fail(attr_id != NULL, NULL);
270 g_return_val_if_fail(attr_name != NULL, NULL);
271 g_return_val_if_fail(attr_value != NULL, NULL);
273 status_type = purple_status_type_new_full(primitive, id, name, saveable,
274 user_settable, independent);
276 /* Add the first attribute */
277 purple_status_type_add_attr(status_type, attr_id, attr_name, attr_value);
279 va_start(args, attr_value);
280 purple_status_type_add_attrs_vargs(status_type, args);
281 va_end(args);
283 return status_type;
286 void
287 purple_status_type_destroy(PurpleStatusType *status_type)
289 g_return_if_fail(status_type != NULL);
291 g_free(status_type->id);
292 g_free(status_type->name);
293 g_free(status_type->primary_attr_id);
295 g_list_foreach(status_type->attrs, (GFunc)purple_status_attr_destroy, NULL);
296 g_list_free(status_type->attrs);
298 PURPLE_DBUS_UNREGISTER_POINTER(status_type);
299 g_free(status_type);
302 void
303 purple_status_type_set_primary_attr(PurpleStatusType *status_type, const char *id)
305 g_return_if_fail(status_type != NULL);
307 g_free(status_type->primary_attr_id);
308 status_type->primary_attr_id = g_strdup(id);
311 void
312 purple_status_type_add_attr(PurpleStatusType *status_type, const char *id,
313 const char *name, PurpleValue *value)
315 PurpleStatusAttr *attr;
317 g_return_if_fail(status_type != NULL);
318 g_return_if_fail(id != NULL);
319 g_return_if_fail(name != NULL);
320 g_return_if_fail(value != NULL);
322 attr = purple_status_attr_new(id, name, value);
324 status_type->attrs = g_list_append(status_type->attrs, attr);
327 void
328 purple_status_type_add_attrs_vargs(PurpleStatusType *status_type, va_list args)
330 const char *id, *name;
331 PurpleValue *value;
333 g_return_if_fail(status_type != NULL);
335 while ((id = va_arg(args, const char *)) != NULL)
337 name = va_arg(args, const char *);
338 g_return_if_fail(name != NULL);
340 value = va_arg(args, PurpleValue *);
341 g_return_if_fail(value != NULL);
343 purple_status_type_add_attr(status_type, id, name, value);
347 void
348 purple_status_type_add_attrs(PurpleStatusType *status_type, const char *id,
349 const char *name, PurpleValue *value, ...)
351 va_list args;
353 g_return_if_fail(status_type != NULL);
354 g_return_if_fail(id != NULL);
355 g_return_if_fail(name != NULL);
356 g_return_if_fail(value != NULL);
358 /* Add the first attribute */
359 purple_status_type_add_attr(status_type, id, name, value);
361 va_start(args, value);
362 purple_status_type_add_attrs_vargs(status_type, args);
363 va_end(args);
366 PurpleStatusPrimitive
367 purple_status_type_get_primitive(const PurpleStatusType *status_type)
369 g_return_val_if_fail(status_type != NULL, PURPLE_STATUS_UNSET);
371 return status_type->primitive;
374 const char *
375 purple_status_type_get_id(const PurpleStatusType *status_type)
377 g_return_val_if_fail(status_type != NULL, NULL);
379 return status_type->id;
382 const char *
383 purple_status_type_get_name(const PurpleStatusType *status_type)
385 g_return_val_if_fail(status_type != NULL, NULL);
387 return status_type->name;
390 gboolean
391 purple_status_type_is_saveable(const PurpleStatusType *status_type)
393 g_return_val_if_fail(status_type != NULL, FALSE);
395 return status_type->saveable;
398 gboolean
399 purple_status_type_is_user_settable(const PurpleStatusType *status_type)
401 g_return_val_if_fail(status_type != NULL, FALSE);
403 return status_type->user_settable;
406 gboolean
407 purple_status_type_is_independent(const PurpleStatusType *status_type)
409 g_return_val_if_fail(status_type != NULL, FALSE);
411 return status_type->independent;
414 gboolean
415 purple_status_type_is_exclusive(const PurpleStatusType *status_type)
417 g_return_val_if_fail(status_type != NULL, FALSE);
419 return !status_type->independent;
422 gboolean
423 purple_status_type_is_available(const PurpleStatusType *status_type)
425 PurpleStatusPrimitive primitive;
427 g_return_val_if_fail(status_type != NULL, FALSE);
429 primitive = purple_status_type_get_primitive(status_type);
431 return (primitive == PURPLE_STATUS_AVAILABLE);
434 const char *
435 purple_status_type_get_primary_attr(const PurpleStatusType *status_type)
437 g_return_val_if_fail(status_type != NULL, NULL);
439 return status_type->primary_attr_id;
442 PurpleStatusAttr *
443 purple_status_type_get_attr(const PurpleStatusType *status_type, const char *id)
445 GList *l;
447 g_return_val_if_fail(status_type != NULL, NULL);
448 g_return_val_if_fail(id != NULL, NULL);
450 for (l = status_type->attrs; l != NULL; l = l->next)
452 PurpleStatusAttr *attr = (PurpleStatusAttr *)l->data;
454 if (!strcmp(purple_status_attr_get_id(attr), id))
455 return attr;
458 return NULL;
461 GList *
462 purple_status_type_get_attrs(const PurpleStatusType *status_type)
464 g_return_val_if_fail(status_type != NULL, NULL);
466 return status_type->attrs;
469 const PurpleStatusType *
470 purple_status_type_find_with_id(GList *status_types, const char *id)
472 PurpleStatusType *status_type;
474 g_return_val_if_fail(id != NULL, NULL);
476 while (status_types != NULL)
478 status_type = status_types->data;
480 if (!strcmp(id, status_type->id))
481 return status_type;
483 status_types = status_types->next;
486 return NULL;
490 /**************************************************************************
491 * PurpleStatusAttr API
492 **************************************************************************/
493 PurpleStatusAttr *
494 purple_status_attr_new(const char *id, const char *name, PurpleValue *value_type)
496 PurpleStatusAttr *attr;
498 g_return_val_if_fail(id != NULL, NULL);
499 g_return_val_if_fail(name != NULL, NULL);
500 g_return_val_if_fail(value_type != NULL, NULL);
502 attr = g_new0(PurpleStatusAttr, 1);
503 PURPLE_DBUS_REGISTER_POINTER(attr, PurpleStatusAttr);
505 attr->id = g_strdup(id);
506 attr->name = g_strdup(name);
507 attr->value_type = value_type;
509 return attr;
512 void
513 purple_status_attr_destroy(PurpleStatusAttr *attr)
515 g_return_if_fail(attr != NULL);
517 g_free(attr->id);
518 g_free(attr->name);
520 purple_value_destroy(attr->value_type);
522 PURPLE_DBUS_UNREGISTER_POINTER(attr);
523 g_free(attr);
526 const char *
527 purple_status_attr_get_id(const PurpleStatusAttr *attr)
529 g_return_val_if_fail(attr != NULL, NULL);
531 return attr->id;
534 const char *
535 purple_status_attr_get_name(const PurpleStatusAttr *attr)
537 g_return_val_if_fail(attr != NULL, NULL);
539 return attr->name;
542 PurpleValue *
543 purple_status_attr_get_value(const PurpleStatusAttr *attr)
545 g_return_val_if_fail(attr != NULL, NULL);
547 return attr->value_type;
551 /**************************************************************************
552 * PurpleStatus API
553 **************************************************************************/
554 PurpleStatus *
555 purple_status_new(PurpleStatusType *status_type, PurplePresence *presence)
557 PurpleStatus *status;
558 GList *l;
560 g_return_val_if_fail(status_type != NULL, NULL);
561 g_return_val_if_fail(presence != NULL, NULL);
563 status = g_new0(PurpleStatus, 1);
564 PURPLE_DBUS_REGISTER_POINTER(status, PurpleStatus);
566 status->type = status_type;
567 status->presence = presence;
569 status->attr_values =
570 g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
571 (GDestroyNotify)purple_value_destroy);
573 for (l = purple_status_type_get_attrs(status_type); l != NULL; l = l->next)
575 PurpleStatusAttr *attr = (PurpleStatusAttr *)l->data;
576 PurpleValue *value = purple_status_attr_get_value(attr);
577 PurpleValue *new_value = purple_value_dup(value);
579 g_hash_table_insert(status->attr_values,
580 (char *)purple_status_attr_get_id(attr),
581 new_value);
584 return status;
588 * TODO: If the PurpleStatus is in a PurplePresence, then
589 * remove it from the PurplePresence?
591 void
592 purple_status_destroy(PurpleStatus *status)
594 g_return_if_fail(status != NULL);
596 g_hash_table_destroy(status->attr_values);
598 PURPLE_DBUS_UNREGISTER_POINTER(status);
599 g_free(status);
602 static void
603 notify_buddy_status_update(PurpleBuddy *buddy, PurplePresence *presence,
604 PurpleStatus *old_status, PurpleStatus *new_status)
606 if (purple_prefs_get_bool("/purple/logging/log_system"))
608 time_t current_time = time(NULL);
609 const char *buddy_alias = purple_buddy_get_alias(buddy);
610 char *tmp, *logtmp;
611 PurpleLog *log;
613 if (old_status != NULL)
615 tmp = g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias, buddy->name,
616 purple_status_get_name(old_status),
617 purple_status_get_name(new_status));
618 logtmp = g_markup_escape_text(tmp, -1);
620 else
622 /* old_status == NULL when an independent status is toggled. */
624 if (purple_status_is_active(new_status))
626 tmp = g_strdup_printf(_("%s (%s) is now %s"), buddy_alias, buddy->name,
627 purple_status_get_name(new_status));
628 logtmp = g_markup_escape_text(tmp, -1);
630 else
632 tmp = g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias, buddy->name,
633 purple_status_get_name(new_status));
634 logtmp = g_markup_escape_text(tmp, -1);
638 log = purple_account_get_log(buddy->account, FALSE);
639 if (log != NULL)
641 purple_log_write(log, PURPLE_MESSAGE_SYSTEM, buddy_alias,
642 current_time, logtmp);
645 g_free(tmp);
646 g_free(logtmp);
650 static void
651 notify_status_update(PurplePresence *presence, PurpleStatus *old_status,
652 PurpleStatus *new_status)
654 PurplePresenceContext context = purple_presence_get_context(presence);
656 if (context == PURPLE_PRESENCE_CONTEXT_ACCOUNT)
658 PurpleAccount *account = purple_presence_get_account(presence);
659 PurpleAccountUiOps *ops = purple_accounts_get_ui_ops();
661 if (purple_account_get_enabled(account, purple_core_get_ui()))
662 purple_prpl_change_account_status(account, old_status, new_status);
664 if (ops != NULL && ops->status_changed != NULL)
666 ops->status_changed(account, new_status);
669 else if (context == PURPLE_PRESENCE_CONTEXT_BUDDY)
671 notify_buddy_status_update(purple_presence_get_buddy(presence), presence,
672 old_status, new_status);
676 static void
677 status_has_changed(PurpleStatus *status)
679 PurplePresence *presence;
680 PurpleStatus *old_status;
682 presence = purple_status_get_presence(status);
685 * If this status is exclusive, then we must be setting it to "active."
686 * Since we are setting it to active, we want to set the currently
687 * active status to "inactive."
689 if (purple_status_is_exclusive(status))
691 old_status = purple_presence_get_active_status(presence);
692 if (old_status != NULL && (old_status != status))
693 old_status->active = FALSE;
694 presence->active_status = status;
696 else
697 old_status = NULL;
699 notify_status_update(presence, old_status, status);
702 void
703 purple_status_set_active(PurpleStatus *status, gboolean active)
705 purple_status_set_active_with_attrs_list(status, active, NULL);
709 * This used to parse the va_list directly, but now it creates a GList
710 * and passes it to purple_status_set_active_with_attrs_list(). That
711 * function was created because accounts.c needs to pass a GList of
712 * attributes to the status API.
714 void
715 purple_status_set_active_with_attrs(PurpleStatus *status, gboolean active, va_list args)
717 GList *attrs = NULL;
718 const gchar *id;
719 gpointer data;
721 while ((id = va_arg(args, const char *)) != NULL)
723 attrs = g_list_append(attrs, (char *)id);
724 data = va_arg(args, void *);
725 attrs = g_list_append(attrs, data);
727 purple_status_set_active_with_attrs_list(status, active, attrs);
728 g_list_free(attrs);
731 void
732 purple_status_set_active_with_attrs_list(PurpleStatus *status, gboolean active,
733 GList *attrs)
735 gboolean changed = FALSE;
736 GList *l;
737 GList *specified_attr_ids = NULL;
738 PurpleStatusType *status_type;
740 g_return_if_fail(status != NULL);
742 if (!active && purple_status_is_exclusive(status))
744 purple_debug_error("status",
745 "Cannot deactivate an exclusive status (%s).\n",
746 purple_status_get_id(status));
747 return;
750 if (status->active != active)
752 changed = TRUE;
755 status->active = active;
757 /* Set any attributes */
758 l = attrs;
759 while (l != NULL)
761 const gchar *id;
762 PurpleValue *value;
764 id = l->data;
765 l = l->next;
766 value = purple_status_get_attr_value(status, id);
767 if (value == NULL)
769 purple_debug_warning("status", "The attribute \"%s\" on the status \"%s\" is "
770 "not supported.\n", id, status->type->name);
771 /* Skip over the data and move on to the next attribute */
772 l = l->next;
773 continue;
776 specified_attr_ids = g_list_prepend(specified_attr_ids, (gpointer)id);
778 if (value->type == PURPLE_TYPE_STRING)
780 const gchar *string_data = l->data;
781 l = l->next;
782 if (((string_data == NULL) && (value->data.string_data == NULL)) ||
783 ((string_data != NULL) && (value->data.string_data != NULL) &&
784 !strcmp(string_data, value->data.string_data)))
786 continue;
788 purple_status_set_attr_string(status, id, string_data);
789 changed = TRUE;
791 else if (value->type == PURPLE_TYPE_INT)
793 int int_data = GPOINTER_TO_INT(l->data);
794 l = l->next;
795 if (int_data == value->data.int_data)
796 continue;
797 purple_status_set_attr_int(status, id, int_data);
798 changed = TRUE;
800 else if (value->type == PURPLE_TYPE_BOOLEAN)
802 gboolean boolean_data = GPOINTER_TO_INT(l->data);
803 l = l->next;
804 if (boolean_data == value->data.boolean_data)
805 continue;
806 purple_status_set_attr_boolean(status, id, boolean_data);
807 changed = TRUE;
809 else
811 /* We don't know what the data is--skip over it */
812 l = l->next;
816 /* Reset any unspecified attributes to their default value */
817 status_type = purple_status_get_type(status);
818 l = purple_status_type_get_attrs(status_type);
819 while (l != NULL) {
820 PurpleStatusAttr *attr;
822 attr = l->data;
823 l = l->next;
825 if (!g_list_find_custom(specified_attr_ids, attr->id, (GCompareFunc)strcmp)) {
826 PurpleValue *default_value;
827 default_value = purple_status_attr_get_value(attr);
828 if (default_value->type == PURPLE_TYPE_STRING) {
829 const char *cur = purple_status_get_attr_string(status, attr->id);
830 const char *def = purple_value_get_string(default_value);
831 if ((cur == NULL && def == NULL)
832 || (cur != NULL && def != NULL
833 && !strcmp(cur, def))) {
834 continue;
837 purple_status_set_attr_string(status, attr->id, def);
838 } else if (default_value->type == PURPLE_TYPE_INT) {
839 int cur = purple_status_get_attr_int(status, attr->id);
840 int def = purple_value_get_int(default_value);
841 if (cur == def)
842 continue;
844 purple_status_set_attr_int(status, attr->id, def);
845 } else if (default_value->type == PURPLE_TYPE_BOOLEAN) {
846 gboolean cur = purple_status_get_attr_boolean(status, attr->id);
847 gboolean def = purple_value_get_boolean(default_value);
848 if (cur == def)
849 continue;
851 purple_status_set_attr_boolean(status, attr->id, def);
853 changed = TRUE;
856 g_list_free(specified_attr_ids);
858 if (!changed)
859 return;
860 status_has_changed(status);
863 void
864 purple_status_set_attr_boolean(PurpleStatus *status, const char *id,
865 gboolean value)
867 PurpleValue *attr_value;
869 g_return_if_fail(status != NULL);
870 g_return_if_fail(id != NULL);
872 /* Make sure this attribute exists and is the correct type. */
873 attr_value = purple_status_get_attr_value(status, id);
874 g_return_if_fail(attr_value != NULL);
875 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_BOOLEAN);
877 purple_value_set_boolean(attr_value, value);
880 void
881 purple_status_set_attr_int(PurpleStatus *status, const char *id, int value)
883 PurpleValue *attr_value;
885 g_return_if_fail(status != NULL);
886 g_return_if_fail(id != NULL);
888 /* Make sure this attribute exists and is the correct type. */
889 attr_value = purple_status_get_attr_value(status, id);
890 g_return_if_fail(attr_value != NULL);
891 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_INT);
893 purple_value_set_int(attr_value, value);
896 void
897 purple_status_set_attr_string(PurpleStatus *status, const char *id,
898 const char *value)
900 PurpleValue *attr_value;
902 g_return_if_fail(status != NULL);
903 g_return_if_fail(id != NULL);
905 /* Make sure this attribute exists and is the correct type. */
906 attr_value = purple_status_get_attr_value(status, id);
907 /* This used to be g_return_if_fail, but it's failing a LOT, so
908 * let's generate a log error for now. */
909 /* g_return_if_fail(attr_value != NULL); */
910 if (attr_value == NULL) {
911 purple_debug_error("status",
912 "Attempted to set status attribute '%s' for "
913 "status '%s', which is not legal. Fix "
914 "this!\n", id,
915 purple_status_type_get_name(purple_status_get_type(status)));
916 return;
918 g_return_if_fail(purple_value_get_type(attr_value) == PURPLE_TYPE_STRING);
920 /* XXX: Check if the value has actually changed. If it has, and the status
921 * is active, should this trigger 'status_has_changed'? */
922 purple_value_set_string(attr_value, value);
925 PurpleStatusType *
926 purple_status_get_type(const PurpleStatus *status)
928 g_return_val_if_fail(status != NULL, NULL);
930 return status->type;
933 PurplePresence *
934 purple_status_get_presence(const PurpleStatus *status)
936 g_return_val_if_fail(status != NULL, NULL);
938 return status->presence;
941 const char *
942 purple_status_get_id(const PurpleStatus *status)
944 g_return_val_if_fail(status != NULL, NULL);
946 return purple_status_type_get_id(purple_status_get_type(status));
949 const char *
950 purple_status_get_name(const PurpleStatus *status)
952 g_return_val_if_fail(status != NULL, NULL);
954 return purple_status_type_get_name(purple_status_get_type(status));
957 gboolean
958 purple_status_is_independent(const PurpleStatus *status)
960 g_return_val_if_fail(status != NULL, FALSE);
962 return purple_status_type_is_independent(purple_status_get_type(status));
965 gboolean
966 purple_status_is_exclusive(const PurpleStatus *status)
968 g_return_val_if_fail(status != NULL, FALSE);
970 return purple_status_type_is_exclusive(purple_status_get_type(status));
973 gboolean
974 purple_status_is_available(const PurpleStatus *status)
976 g_return_val_if_fail(status != NULL, FALSE);
978 return purple_status_type_is_available(purple_status_get_type(status));
981 gboolean
982 purple_status_is_active(const PurpleStatus *status)
984 g_return_val_if_fail(status != NULL, FALSE);
986 return status->active;
989 gboolean
990 purple_status_is_online(const PurpleStatus *status)
992 PurpleStatusPrimitive primitive;
994 g_return_val_if_fail( status != NULL, FALSE);
996 primitive = purple_status_type_get_primitive(purple_status_get_type(status));
998 return (primitive != PURPLE_STATUS_UNSET &&
999 primitive != PURPLE_STATUS_OFFLINE);
1002 PurpleValue *
1003 purple_status_get_attr_value(const PurpleStatus *status, const char *id)
1005 g_return_val_if_fail(status != NULL, NULL);
1006 g_return_val_if_fail(id != NULL, NULL);
1008 return (PurpleValue *)g_hash_table_lookup(status->attr_values, id);
1011 gboolean
1012 purple_status_get_attr_boolean(const PurpleStatus *status, const char *id)
1014 const PurpleValue *value;
1016 g_return_val_if_fail(status != NULL, FALSE);
1017 g_return_val_if_fail(id != NULL, FALSE);
1019 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1020 return FALSE;
1022 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_BOOLEAN, FALSE);
1024 return purple_value_get_boolean(value);
1028 purple_status_get_attr_int(const PurpleStatus *status, const char *id)
1030 const PurpleValue *value;
1032 g_return_val_if_fail(status != NULL, 0);
1033 g_return_val_if_fail(id != NULL, 0);
1035 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1036 return 0;
1038 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_INT, 0);
1040 return purple_value_get_int(value);
1043 const char *
1044 purple_status_get_attr_string(const PurpleStatus *status, const char *id)
1046 const PurpleValue *value;
1048 g_return_val_if_fail(status != NULL, NULL);
1049 g_return_val_if_fail(id != NULL, NULL);
1051 if ((value = purple_status_get_attr_value(status, id)) == NULL)
1052 return NULL;
1054 g_return_val_if_fail(purple_value_get_type(value) == PURPLE_TYPE_STRING, NULL);
1056 return purple_value_get_string(value);
1059 gint
1060 purple_status_compare(const PurpleStatus *status1, const PurpleStatus *status2)
1062 PurpleStatusType *type1, *type2;
1063 int score1 = 0, score2 = 0;
1065 if ((status1 == NULL && status2 == NULL) ||
1066 (status1 == status2))
1068 return 0;
1070 else if (status1 == NULL)
1071 return 1;
1072 else if (status2 == NULL)
1073 return -1;
1075 type1 = purple_status_get_type(status1);
1076 type2 = purple_status_get_type(status2);
1078 if (purple_status_is_active(status1))
1079 score1 = primitive_scores[purple_status_type_get_primitive(type1)];
1081 if (purple_status_is_active(status2))
1082 score2 = primitive_scores[purple_status_type_get_primitive(type2)];
1084 if (score1 > score2)
1085 return -1;
1086 else if (score1 < score2)
1087 return 1;
1089 return 0;
1093 /**************************************************************************
1094 * PurplePresence API
1095 **************************************************************************/
1096 PurplePresence *
1097 purple_presence_new(PurplePresenceContext context)
1099 PurplePresence *presence;
1101 g_return_val_if_fail(context != PURPLE_PRESENCE_CONTEXT_UNSET, NULL);
1103 presence = g_new0(PurplePresence, 1);
1104 PURPLE_DBUS_REGISTER_POINTER(presence, PurplePresence);
1106 presence->context = context;
1108 presence->status_table =
1109 g_hash_table_new_full(g_str_hash, g_str_equal,
1110 g_free, NULL);
1112 return presence;
1115 PurplePresence *
1116 purple_presence_new_for_account(PurpleAccount *account)
1118 PurplePresence *presence = NULL;
1119 g_return_val_if_fail(account != NULL, NULL);
1121 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_ACCOUNT);
1122 presence->u.account = account;
1123 presence->statuses = purple_prpl_get_statuses(account, presence);
1125 return presence;
1128 PurplePresence *
1129 purple_presence_new_for_conv(PurpleConversation *conv)
1131 PurplePresence *presence;
1133 g_return_val_if_fail(conv != NULL, NULL);
1135 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_CONV);
1136 presence->u.chat.conv = conv;
1137 /* presence->statuses = purple_prpl_get_statuses(conv->account, presence); ? */
1139 return presence;
1142 PurplePresence *
1143 purple_presence_new_for_buddy(PurpleBuddy *buddy)
1145 PurplePresence *presence;
1146 PurpleAccount *account;
1148 g_return_val_if_fail(buddy != NULL, NULL);
1149 account = buddy->account;
1151 presence = purple_presence_new(PURPLE_PRESENCE_CONTEXT_BUDDY);
1153 presence->u.buddy.name = g_strdup(buddy->name);
1154 presence->u.buddy.account = buddy->account;
1155 presence->statuses = purple_prpl_get_statuses(buddy->account, presence);
1157 presence->u.buddy.buddy = buddy;
1159 return presence;
1162 void
1163 purple_presence_destroy(PurplePresence *presence)
1165 g_return_if_fail(presence != NULL);
1167 if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_BUDDY)
1169 g_free(presence->u.buddy.name);
1171 else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_CONV)
1173 g_free(presence->u.chat.user);
1176 g_list_foreach(presence->statuses, (GFunc)purple_status_destroy, NULL);
1177 g_list_free(presence->statuses);
1179 g_hash_table_destroy(presence->status_table);
1181 PURPLE_DBUS_UNREGISTER_POINTER(presence);
1182 g_free(presence);
1185 void
1186 purple_presence_add_status(PurplePresence *presence, PurpleStatus *status)
1188 g_return_if_fail(presence != NULL);
1189 g_return_if_fail(status != NULL);
1191 presence->statuses = g_list_append(presence->statuses, status);
1193 g_hash_table_insert(presence->status_table,
1194 g_strdup(purple_status_get_id(status)), status);
1197 void
1198 purple_presence_add_list(PurplePresence *presence, GList *source_list)
1200 GList *l;
1202 g_return_if_fail(presence != NULL);
1203 g_return_if_fail(source_list != NULL);
1205 for (l = source_list; l != NULL; l = l->next)
1206 purple_presence_add_status(presence, (PurpleStatus *)l->data);
1209 void
1210 purple_presence_set_status_active(PurplePresence *presence, const char *status_id,
1211 gboolean active)
1213 PurpleStatus *status;
1215 g_return_if_fail(presence != NULL);
1216 g_return_if_fail(status_id != NULL);
1218 status = purple_presence_get_status(presence, status_id);
1220 g_return_if_fail(status != NULL);
1221 /* TODO: Should we do the following? */
1222 /* g_return_if_fail(active == status->active); */
1224 if (purple_status_is_exclusive(status))
1226 if (!active)
1228 purple_debug_warning("status",
1229 "Attempted to set a non-independent status "
1230 "(%s) inactive. Only independent statuses "
1231 "can be specifically marked inactive.",
1232 status_id);
1233 return;
1237 purple_status_set_active(status, active);
1240 void
1241 purple_presence_switch_status(PurplePresence *presence, const char *status_id)
1243 purple_presence_set_status_active(presence, status_id, TRUE);
1246 static void
1247 update_buddy_idle(PurpleBuddy *buddy, PurplePresence *presence,
1248 time_t current_time, gboolean old_idle, gboolean idle)
1250 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
1252 if (!old_idle && idle)
1254 if (purple_prefs_get_bool("/purple/logging/log_system"))
1256 PurpleLog *log = purple_account_get_log(buddy->account, FALSE);
1258 if (log != NULL)
1260 char *tmp, *tmp2;
1261 tmp = g_strdup_printf(_("%s became idle"),
1262 purple_buddy_get_alias(buddy));
1263 tmp2 = g_markup_escape_text(tmp, -1);
1264 g_free(tmp);
1266 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1267 purple_buddy_get_alias(buddy), current_time, tmp2);
1268 g_free(tmp2);
1272 else if (old_idle && !idle)
1274 if (purple_prefs_get_bool("/purple/logging/log_system"))
1276 PurpleLog *log = purple_account_get_log(buddy->account, FALSE);
1278 if (log != NULL)
1280 char *tmp, *tmp2;
1281 tmp = g_strdup_printf(_("%s became unidle"),
1282 purple_buddy_get_alias(buddy));
1283 tmp2 = g_markup_escape_text(tmp, -1);
1284 g_free(tmp);
1286 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1287 purple_buddy_get_alias(buddy), current_time, tmp2);
1288 g_free(tmp2);
1293 if (old_idle != idle)
1294 purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
1295 old_idle, idle);
1297 purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
1299 /* Should this be done here? It'd perhaps make more sense to
1300 * connect to buddy-[un]idle signals and update from there
1303 if (ops != NULL && ops->update != NULL)
1304 ops->update(purple_get_blist(), (PurpleBlistNode *)buddy);
1307 void
1308 purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time)
1310 gboolean old_idle;
1311 time_t current_time;
1313 g_return_if_fail(presence != NULL);
1315 if (presence->idle == idle && presence->idle_time == idle_time)
1316 return;
1318 old_idle = presence->idle;
1319 presence->idle = idle;
1320 presence->idle_time = (idle ? idle_time : 0);
1322 current_time = time(NULL);
1324 if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_BUDDY)
1326 update_buddy_idle(purple_presence_get_buddy(presence), presence, current_time,
1327 old_idle, idle);
1329 else if (purple_presence_get_context(presence) == PURPLE_PRESENCE_CONTEXT_ACCOUNT)
1331 PurpleAccount *account;
1332 PurpleConnection *gc = NULL;
1333 PurplePlugin *prpl = NULL;
1334 PurplePluginProtocolInfo *prpl_info = NULL;
1336 account = purple_presence_get_account(presence);
1338 if (purple_prefs_get_bool("/purple/logging/log_system"))
1340 PurpleLog *log = purple_account_get_log(account, FALSE);
1342 if (log != NULL)
1344 char *msg, *tmp;
1346 if (idle)
1347 tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
1348 else
1349 tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
1351 msg = g_markup_escape_text(tmp, -1);
1352 g_free(tmp);
1353 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
1354 purple_account_get_username(account),
1355 (idle ? idle_time : current_time), msg);
1356 g_free(msg);
1360 gc = purple_account_get_connection(account);
1362 if(gc)
1363 prpl = purple_connection_get_prpl(gc);
1365 if(PURPLE_CONNECTION_IS_CONNECTED(gc) && prpl != NULL)
1366 prpl_info = PURPLE_PLUGIN_PROTOCOL_INFO(prpl);
1368 if (prpl_info && prpl_info->set_idle)
1369 prpl_info->set_idle(gc, (idle ? (current_time - idle_time) : 0));
1373 void
1374 purple_presence_set_login_time(PurplePresence *presence, time_t login_time)
1376 g_return_if_fail(presence != NULL);
1378 if (presence->login_time == login_time)
1379 return;
1381 presence->login_time = login_time;
1384 PurplePresenceContext
1385 purple_presence_get_context(const PurplePresence *presence)
1387 g_return_val_if_fail(presence != NULL, PURPLE_PRESENCE_CONTEXT_UNSET);
1389 return presence->context;
1392 PurpleAccount *
1393 purple_presence_get_account(const PurplePresence *presence)
1395 PurplePresenceContext context;
1397 g_return_val_if_fail(presence != NULL, NULL);
1399 context = purple_presence_get_context(presence);
1401 g_return_val_if_fail(context == PURPLE_PRESENCE_CONTEXT_ACCOUNT ||
1402 context == PURPLE_PRESENCE_CONTEXT_BUDDY, NULL);
1404 return presence->u.account;
1407 PurpleConversation *
1408 purple_presence_get_conversation(const PurplePresence *presence)
1410 g_return_val_if_fail(presence != NULL, NULL);
1411 g_return_val_if_fail(purple_presence_get_context(presence) ==
1412 PURPLE_PRESENCE_CONTEXT_CONV, NULL);
1414 return presence->u.chat.conv;
1417 const char *
1418 purple_presence_get_chat_user(const PurplePresence *presence)
1420 g_return_val_if_fail(presence != NULL, NULL);
1421 g_return_val_if_fail(purple_presence_get_context(presence) ==
1422 PURPLE_PRESENCE_CONTEXT_CONV, NULL);
1424 return presence->u.chat.user;
1427 PurpleBuddy *
1428 purple_presence_get_buddy(const PurplePresence *presence)
1430 g_return_val_if_fail(presence != NULL, NULL);
1431 g_return_val_if_fail(purple_presence_get_context(presence) ==
1432 PURPLE_PRESENCE_CONTEXT_BUDDY, NULL);
1434 return presence->u.buddy.buddy;
1437 GList *
1438 purple_presence_get_statuses(const PurplePresence *presence)
1440 g_return_val_if_fail(presence != NULL, NULL);
1442 return presence->statuses;
1445 PurpleStatus *
1446 purple_presence_get_status(const PurplePresence *presence, const char *status_id)
1448 PurpleStatus *status;
1449 GList *l = NULL;
1451 g_return_val_if_fail(presence != NULL, NULL);
1452 g_return_val_if_fail(status_id != NULL, NULL);
1454 /* What's the purpose of this hash table? */
1455 status = (PurpleStatus *)g_hash_table_lookup(presence->status_table,
1456 status_id);
1458 if (status == NULL) {
1459 for (l = purple_presence_get_statuses(presence);
1460 l != NULL && status == NULL; l = l->next)
1462 PurpleStatus *temp_status = l->data;
1464 if (!strcmp(status_id, purple_status_get_id(temp_status)))
1465 status = temp_status;
1468 if (status != NULL)
1469 g_hash_table_insert(presence->status_table,
1470 g_strdup(purple_status_get_id(status)), status);
1473 return status;
1476 PurpleStatus *
1477 purple_presence_get_active_status(const PurplePresence *presence)
1479 g_return_val_if_fail(presence != NULL, NULL);
1481 return presence->active_status;
1484 gboolean
1485 purple_presence_is_available(const PurplePresence *presence)
1487 PurpleStatus *status;
1489 g_return_val_if_fail(presence != NULL, FALSE);
1491 status = purple_presence_get_active_status(presence);
1493 return ((status != NULL && purple_status_is_available(status)) &&
1494 !purple_presence_is_idle(presence));
1497 gboolean
1498 purple_presence_is_online(const PurplePresence *presence)
1500 PurpleStatus *status;
1502 g_return_val_if_fail(presence != NULL, FALSE);
1504 if ((status = purple_presence_get_active_status(presence)) == NULL)
1505 return FALSE;
1507 return purple_status_is_online(status);
1510 gboolean
1511 purple_presence_is_status_active(const PurplePresence *presence,
1512 const char *status_id)
1514 PurpleStatus *status;
1516 g_return_val_if_fail(presence != NULL, FALSE);
1517 g_return_val_if_fail(status_id != NULL, FALSE);
1519 status = purple_presence_get_status(presence, status_id);
1521 return (status != NULL && purple_status_is_active(status));
1524 gboolean
1525 purple_presence_is_status_primitive_active(const PurplePresence *presence,
1526 PurpleStatusPrimitive primitive)
1528 GList *l;
1530 g_return_val_if_fail(presence != NULL, FALSE);
1531 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, FALSE);
1533 for (l = purple_presence_get_statuses(presence);
1534 l != NULL; l = l->next) {
1535 PurpleStatus *temp_status = l->data;
1536 PurpleStatusType *type = purple_status_get_type(temp_status);
1538 if (purple_status_type_get_primitive(type) == primitive &&
1539 purple_status_is_active(temp_status))
1540 return TRUE;
1542 return FALSE;
1545 gboolean
1546 purple_presence_is_idle(const PurplePresence *presence)
1548 g_return_val_if_fail(presence != NULL, FALSE);
1550 return purple_presence_is_online(presence) && presence->idle;
1553 time_t
1554 purple_presence_get_idle_time(const PurplePresence *presence)
1556 g_return_val_if_fail(presence != NULL, 0);
1558 return presence->idle_time;
1561 time_t
1562 purple_presence_get_login_time(const PurplePresence *presence)
1564 g_return_val_if_fail(presence != NULL, 0);
1566 return purple_presence_is_online(presence) ? presence->login_time : 0;
1569 static int
1570 purple_presence_compute_score(const PurplePresence *presence)
1572 GList *l;
1573 int score = 0;
1575 for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) {
1576 PurpleStatus *status = (PurpleStatus *)l->data;
1577 PurpleStatusType *type = purple_status_get_type(status);
1579 if (purple_status_is_active(status)) {
1580 score += primitive_scores[purple_status_type_get_primitive(type)];
1581 if (!purple_status_is_online(status)) {
1582 PurpleBuddy *b = purple_presence_get_buddy(presence);
1583 if (b && purple_account_supports_offline_message(purple_buddy_get_account(b), b))
1584 score += primitive_scores[SCORE_OFFLINE_MESSAGE];
1588 score += purple_account_get_int(purple_presence_get_account(presence), "score", 0);
1589 if (purple_presence_is_idle(presence))
1590 score += primitive_scores[SCORE_IDLE];
1591 return score;
1594 gint
1595 purple_presence_compare(const PurplePresence *presence1,
1596 const PurplePresence *presence2)
1598 time_t idle_time_1, idle_time_2;
1599 int score1 = 0, score2 = 0;
1601 if (presence1 == presence2)
1602 return 0;
1603 else if (presence1 == NULL)
1604 return 1;
1605 else if (presence2 == NULL)
1606 return -1;
1608 if (purple_presence_is_online(presence1) &&
1609 !purple_presence_is_online(presence2))
1610 return -1;
1611 else if (purple_presence_is_online(presence2) &&
1612 !purple_presence_is_online(presence1))
1613 return 1;
1615 /* Compute the score of the first set of statuses. */
1616 score1 = purple_presence_compute_score(presence1);
1618 /* Compute the score of the second set of statuses. */
1619 score2 = purple_presence_compute_score(presence2);
1621 idle_time_1 = time(NULL) - purple_presence_get_idle_time(presence1);
1622 idle_time_2 = time(NULL) - purple_presence_get_idle_time(presence2);
1624 if (idle_time_1 > idle_time_2)
1625 score1 += primitive_scores[SCORE_IDLE_TIME];
1626 else if (idle_time_1 < idle_time_2)
1627 score2 += primitive_scores[SCORE_IDLE_TIME];
1629 if (score1 < score2)
1630 return 1;
1631 else if (score1 > score2)
1632 return -1;
1634 return 0;
1638 /**************************************************************************
1639 * Status subsystem
1640 **************************************************************************/
1641 static void
1642 score_pref_changed_cb(const char *name, PurplePrefType type,
1643 gconstpointer value, gpointer data)
1645 int index = GPOINTER_TO_INT(data);
1647 primitive_scores[index] = GPOINTER_TO_INT(value);
1650 void *
1651 purple_status_get_handle(void) {
1652 static int handle;
1654 return &handle;
1657 void
1658 purple_status_init(void)
1660 void *handle = purple_status_get_handle;
1662 purple_prefs_add_none("/purple/status");
1663 purple_prefs_add_none("/purple/status/scores");
1665 purple_prefs_add_int("/purple/status/scores/offline",
1666 primitive_scores[PURPLE_STATUS_OFFLINE]);
1667 purple_prefs_add_int("/purple/status/scores/available",
1668 primitive_scores[PURPLE_STATUS_AVAILABLE]);
1669 purple_prefs_add_int("/purple/status/scores/invisible",
1670 primitive_scores[PURPLE_STATUS_INVISIBLE]);
1671 purple_prefs_add_int("/purple/status/scores/away",
1672 primitive_scores[PURPLE_STATUS_AWAY]);
1673 purple_prefs_add_int("/purple/status/scores/extended_away",
1674 primitive_scores[PURPLE_STATUS_EXTENDED_AWAY]);
1675 purple_prefs_add_int("/purple/status/scores/idle",
1676 primitive_scores[SCORE_IDLE]);
1677 purple_prefs_add_int("/purple/status/scores/offline_msg",
1678 primitive_scores[SCORE_OFFLINE_MESSAGE]);
1680 purple_prefs_connect_callback(handle, "/purple/status/scores/offline",
1681 score_pref_changed_cb,
1682 GINT_TO_POINTER(PURPLE_STATUS_OFFLINE));
1683 purple_prefs_connect_callback(handle, "/purple/status/scores/available",
1684 score_pref_changed_cb,
1685 GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE));
1686 purple_prefs_connect_callback(handle, "/purple/status/scores/invisible",
1687 score_pref_changed_cb,
1688 GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE));
1689 purple_prefs_connect_callback(handle, "/purple/status/scores/away",
1690 score_pref_changed_cb,
1691 GINT_TO_POINTER(PURPLE_STATUS_AWAY));
1692 purple_prefs_connect_callback(handle, "/purple/status/scores/extended_away",
1693 score_pref_changed_cb,
1694 GINT_TO_POINTER(PURPLE_STATUS_EXTENDED_AWAY));
1695 purple_prefs_connect_callback(handle, "/purple/status/scores/idle",
1696 score_pref_changed_cb,
1697 GINT_TO_POINTER(SCORE_IDLE));
1698 purple_prefs_connect_callback(handle, "/purple/status/scores/offline_msg",
1699 score_pref_changed_cb,
1700 GINT_TO_POINTER(SCORE_OFFLINE_MESSAGE));
1702 purple_prefs_trigger_callback("/purple/status/scores/offline");
1703 purple_prefs_trigger_callback("/purple/status/scores/available");
1704 purple_prefs_trigger_callback("/purple/status/scores/invisible");
1705 purple_prefs_trigger_callback("/purple/status/scores/away");
1706 purple_prefs_trigger_callback("/purple/status/scores/extended_away");
1707 purple_prefs_trigger_callback("/purple/status/scores/idle");
1708 purple_prefs_trigger_callback("/purple/status/scores/offline_msg");
1711 void
1712 purple_status_uninit(void)