3 * Purple is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
22 #include "glibcompat.h"
24 #include "buddylist.h"
31 typedef struct _PurpleStatusPrivate PurpleStatusPrivate
;
36 struct _PurpleStatusType
40 PurpleStatusPrimitive primitive
;
46 gboolean user_settable
;
55 struct _PurpleStatusAttribute
65 * A PurpleStatus can be thought of as an "instance" of a PurpleStatusType.
66 * If you're familiar with object-oriented programming languages
67 * then this should be immediately clear. Say, for example, that
68 * one of your AIM buddies has set himself as "away." You have a
69 * PurpleBuddy node for this person in your buddy list. Purple wants
70 * to mark this buddy as "away," so it creates a new PurpleStatus.
71 * The PurpleStatus has its PurpleStatusType set to the "away" state
72 * for the oscar protocol. The PurpleStatus also contains the buddy's
73 * away message. PurpleStatuses are sometimes saved, depending on
74 * the context. The current PurpleStatuses associated with each of
75 * your accounts are saved so that the next time you start Purple,
76 * your accounts will be set to their last known statuses. There
77 * is also a list of saved statuses that are written to the
78 * status.xml file. Also, each PurpleStatus has a "saveable" boolean.
79 * If "saveable" is set to FALSE then the status is NEVER saved.
80 * All PurpleStatuses should be inside a PurplePresence.
82 * A PurpleStatus is either "independent" or "exclusive."
83 * Independent statuses can be active or inactive and they don't
84 * affect anything else. However, you can only have one exclusive
85 * status per PurplePresence. If you activate one exclusive status,
86 * then the previous exclusive status is automatically deactivated.
88 * A PurplePresence is like a collection of PurpleStatuses (plus some
91 * See <link linkend="libpurple-presence">Presence API</link>
99 * Private data for PurpleStatus
101 struct _PurpleStatusPrivate
103 PurpleStatusType
*status_type
;
104 PurplePresence
*presence
;
109 * The current values of the attributes for this status. The
110 * key is a string containing the name of the attribute. It is
111 * a borrowed reference from the list of attrs in the
112 * PurpleStatusType. The value is a GValue.
114 GHashTable
*attr_values
;
117 /* GObject property enums */
129 PurpleAccount
*account
;
131 } PurpleStatusBuddyKey
;
133 static GParamSpec
*properties
[PROP_LAST
];
135 G_DEFINE_TYPE_WITH_PRIVATE(PurpleStatus
, purple_status
, G_TYPE_OBJECT
);
137 static int primitive_scores
[] =
142 -75, /* unavailable */
145 -200, /* extended away */
149 -10, /* idle, special case. */
150 -5, /* idle time, special case. */
151 10 /* Offline messageable */
155 #define SCORE_IDLE_TIME 10
156 #define SCORE_OFFLINE_MESSAGE 11
158 /**************************************************************************
159 * PurpleStatusPrimitive API
160 **************************************************************************/
161 static struct PurpleStatusPrimitiveMap
163 PurpleStatusPrimitive type
;
167 } const status_primitive_map
[] =
169 { PURPLE_STATUS_UNSET
, "unset", N_("Unset") },
170 { PURPLE_STATUS_OFFLINE
, "offline", N_("Offline") },
171 { PURPLE_STATUS_AVAILABLE
, "available", N_("Available") },
172 { PURPLE_STATUS_UNAVAILABLE
, "unavailable", N_("Do not disturb") },
173 { PURPLE_STATUS_INVISIBLE
, "invisible", N_("Invisible") },
174 { PURPLE_STATUS_AWAY
, "away", N_("Away") },
175 { PURPLE_STATUS_EXTENDED_AWAY
, "extended_away", N_("Extended away") },
176 { PURPLE_STATUS_MOBILE
, "mobile", N_("Mobile") },
177 { PURPLE_STATUS_TUNE
, "tune", N_("Listening to music"), },
178 { PURPLE_STATUS_MOOD
, "mood", N_("Feeling") },
182 _purple_statuses_get_primitive_scores(void)
184 return primitive_scores
;
188 purple_primitive_get_id_from_type(PurpleStatusPrimitive type
)
192 for (i
= 0; i
< PURPLE_STATUS_NUM_PRIMITIVES
; i
++)
194 if (type
== status_primitive_map
[i
].type
)
195 return status_primitive_map
[i
].id
;
198 return status_primitive_map
[0].id
;
202 purple_primitive_get_name_from_type(PurpleStatusPrimitive type
)
206 for (i
= 0; i
< PURPLE_STATUS_NUM_PRIMITIVES
; i
++)
208 if (type
== status_primitive_map
[i
].type
)
209 return _(status_primitive_map
[i
].name
);
212 return _(status_primitive_map
[0].name
);
215 PurpleStatusPrimitive
216 purple_primitive_get_type_from_id(const char *id
)
220 g_return_val_if_fail(id
!= NULL
, PURPLE_STATUS_UNSET
);
222 for (i
= 0; i
< PURPLE_STATUS_NUM_PRIMITIVES
; i
++)
224 if (purple_strequal(id
, status_primitive_map
[i
].id
))
225 return status_primitive_map
[i
].type
;
228 return status_primitive_map
[0].type
;
232 /**************************************************************************
233 * PurpleStatusType API
234 **************************************************************************/
236 purple_status_type_new_full(PurpleStatusPrimitive primitive
, const char *id
,
237 const char *name
, gboolean saveable
,
238 gboolean user_settable
, gboolean independent
)
240 PurpleStatusType
*status_type
;
242 g_return_val_if_fail(primitive
!= PURPLE_STATUS_UNSET
, NULL
);
244 status_type
= g_new0(PurpleStatusType
, 1);
246 status_type
->primitive
= primitive
;
247 status_type
->saveable
= saveable
;
248 status_type
->user_settable
= user_settable
;
249 status_type
->independent
= independent
;
252 status_type
->id
= g_strdup(id
);
254 status_type
->id
= g_strdup(purple_primitive_get_id_from_type(primitive
));
257 status_type
->name
= g_strdup(name
);
259 status_type
->name
= g_strdup(purple_primitive_get_name_from_type(primitive
));
265 purple_status_type_new(PurpleStatusPrimitive primitive
, const char *id
,
266 const char *name
, gboolean user_settable
)
268 g_return_val_if_fail(primitive
!= PURPLE_STATUS_UNSET
, NULL
);
270 return purple_status_type_new_full(primitive
, id
, name
, TRUE
,
271 user_settable
, FALSE
);
275 status_type_add_attr(PurpleStatusType
*status_type
, const char *id
,
276 const char *name
, GValue
*value
)
278 PurpleStatusAttribute
*attr
;
280 g_return_if_fail(status_type
!= NULL
);
281 g_return_if_fail(id
!= NULL
);
282 g_return_if_fail(name
!= NULL
);
283 g_return_if_fail(value
!= NULL
);
285 attr
= purple_status_attribute_new(id
, name
, value
);
287 status_type
->attrs
= g_list_append(status_type
->attrs
, attr
);
291 status_type_add_attrs_vargs(PurpleStatusType
*status_type
, va_list args
)
293 const char *id
, *name
;
296 g_return_if_fail(status_type
!= NULL
);
298 while ((id
= va_arg(args
, const char *)) != NULL
)
300 name
= va_arg(args
, const char *);
301 g_return_if_fail(name
!= NULL
);
303 value
= va_arg(args
, GValue
*);
304 g_return_if_fail(value
!= NULL
);
306 status_type_add_attr(status_type
, id
, name
, value
);
311 purple_status_type_new_with_attrs(PurpleStatusPrimitive primitive
,
312 const char *id
, const char *name
,
313 gboolean saveable
, gboolean user_settable
,
314 gboolean independent
, const char *attr_id
,
315 const char *attr_name
, GValue
*attr_value
,
318 PurpleStatusType
*status_type
;
321 g_return_val_if_fail(primitive
!= PURPLE_STATUS_UNSET
, NULL
);
322 g_return_val_if_fail(attr_id
!= NULL
, NULL
);
323 g_return_val_if_fail(attr_name
!= NULL
, NULL
);
324 g_return_val_if_fail(attr_value
!= NULL
, NULL
);
326 status_type
= purple_status_type_new_full(primitive
, id
, name
, saveable
,
327 user_settable
, independent
);
329 /* Add the first attribute */
330 status_type_add_attr(status_type
, attr_id
, attr_name
, attr_value
);
332 va_start(args
, attr_value
);
333 status_type_add_attrs_vargs(status_type
, args
);
340 purple_status_type_destroy(PurpleStatusType
*status_type
)
342 g_return_if_fail(status_type
!= NULL
);
344 g_free(status_type
->id
);
345 g_free(status_type
->name
);
347 g_list_free_full(status_type
->attrs
,
348 (GDestroyNotify
)purple_status_attribute_destroy
);
353 PurpleStatusPrimitive
354 purple_status_type_get_primitive(const PurpleStatusType
*status_type
)
356 g_return_val_if_fail(status_type
!= NULL
, PURPLE_STATUS_UNSET
);
358 return status_type
->primitive
;
362 purple_status_type_get_id(const PurpleStatusType
*status_type
)
364 g_return_val_if_fail(status_type
!= NULL
, NULL
);
366 return status_type
->id
;
370 purple_status_type_get_name(const PurpleStatusType
*status_type
)
372 g_return_val_if_fail(status_type
!= NULL
, NULL
);
374 return status_type
->name
;
378 purple_status_type_is_saveable(const PurpleStatusType
*status_type
)
380 g_return_val_if_fail(status_type
!= NULL
, FALSE
);
382 return status_type
->saveable
;
386 purple_status_type_is_user_settable(const PurpleStatusType
*status_type
)
388 g_return_val_if_fail(status_type
!= NULL
, FALSE
);
390 return status_type
->user_settable
;
394 purple_status_type_is_independent(const PurpleStatusType
*status_type
)
396 g_return_val_if_fail(status_type
!= NULL
, FALSE
);
398 return status_type
->independent
;
402 purple_status_type_is_exclusive(const PurpleStatusType
*status_type
)
404 g_return_val_if_fail(status_type
!= NULL
, FALSE
);
406 return !status_type
->independent
;
410 purple_status_type_is_available(const PurpleStatusType
*status_type
)
412 PurpleStatusPrimitive primitive
;
414 g_return_val_if_fail(status_type
!= NULL
, FALSE
);
416 primitive
= purple_status_type_get_primitive(status_type
);
418 return (primitive
== PURPLE_STATUS_AVAILABLE
);
421 PurpleStatusAttribute
*
422 purple_status_type_get_attr(const PurpleStatusType
*status_type
, const char *id
)
426 g_return_val_if_fail(status_type
!= NULL
, NULL
);
427 g_return_val_if_fail(id
!= NULL
, NULL
);
429 for (l
= status_type
->attrs
; l
!= NULL
; l
= l
->next
)
431 PurpleStatusAttribute
*attr
= (PurpleStatusAttribute
*)l
->data
;
433 if (purple_strequal(purple_status_attribute_get_id(attr
), id
))
441 purple_status_type_get_attrs(const PurpleStatusType
*status_type
)
443 g_return_val_if_fail(status_type
!= NULL
, NULL
);
445 return status_type
->attrs
;
448 const PurpleStatusType
*
449 purple_status_type_find_with_id(GList
*status_types
, const char *id
)
451 PurpleStatusType
*status_type
;
453 g_return_val_if_fail(id
!= NULL
, NULL
);
455 while (status_types
!= NULL
)
457 status_type
= status_types
->data
;
459 if (purple_strequal(id
, status_type
->id
))
462 status_types
= status_types
->next
;
469 /**************************************************************************
470 * PurpleStatusAttribute API
471 **************************************************************************/
472 PurpleStatusAttribute
*
473 purple_status_attribute_new(const char *id
, const char *name
, GValue
*value_type
)
475 PurpleStatusAttribute
*attr
;
477 g_return_val_if_fail(id
!= NULL
, NULL
);
478 g_return_val_if_fail(name
!= NULL
, NULL
);
479 g_return_val_if_fail(value_type
!= NULL
, NULL
);
481 attr
= g_new0(PurpleStatusAttribute
, 1);
483 attr
->id
= g_strdup(id
);
484 attr
->name
= g_strdup(name
);
485 attr
->value_type
= value_type
;
491 purple_status_attribute_destroy(PurpleStatusAttribute
*attr
)
493 g_return_if_fail(attr
!= NULL
);
498 purple_value_free(attr
->value_type
);
504 purple_status_attribute_get_id(const PurpleStatusAttribute
*attr
)
506 g_return_val_if_fail(attr
!= NULL
, NULL
);
512 purple_status_attribute_get_name(const PurpleStatusAttribute
*attr
)
514 g_return_val_if_fail(attr
!= NULL
, NULL
);
520 purple_status_attribute_get_value(const PurpleStatusAttribute
*attr
)
522 g_return_val_if_fail(attr
!= NULL
, NULL
);
524 return attr
->value_type
;
528 /**************************************************************************
530 **************************************************************************/
532 notify_buddy_status_update(PurpleBuddy
*buddy
, PurplePresence
*presence
,
533 PurpleStatus
*old_status
, PurpleStatus
*new_status
)
535 if (purple_prefs_get_bool("/purple/logging/log_system"))
537 GDateTime
*current_time
= g_date_time_new_now_utc();
538 const char *buddy_alias
= purple_buddy_get_alias(buddy
);
542 if (old_status
!= NULL
)
544 tmp
= g_strdup_printf(_("%s (%s) changed status from %s to %s"), buddy_alias
,
545 purple_buddy_get_name(buddy
),
546 purple_status_get_name(old_status
),
547 purple_status_get_name(new_status
));
548 logtmp
= g_markup_escape_text(tmp
, -1);
552 /* old_status == NULL when an independent status is toggled. */
554 if (purple_status_is_active(new_status
))
556 tmp
= g_strdup_printf(_("%s (%s) is now %s"), buddy_alias
,
557 purple_buddy_get_name(buddy
),
558 purple_status_get_name(new_status
));
559 logtmp
= g_markup_escape_text(tmp
, -1);
563 tmp
= g_strdup_printf(_("%s (%s) is no longer %s"), buddy_alias
,
564 purple_buddy_get_name(buddy
),
565 purple_status_get_name(new_status
));
566 logtmp
= g_markup_escape_text(tmp
, -1);
570 log
= purple_account_get_log(purple_buddy_get_account(buddy
), FALSE
);
573 purple_log_write(log
, PURPLE_MESSAGE_SYSTEM
, buddy_alias
,
574 current_time
, logtmp
);
577 g_date_time_unref(current_time
);
584 notify_status_update(PurplePresence
*presence
, PurpleStatus
*old_status
,
585 PurpleStatus
*new_status
)
587 if (PURPLE_IS_ACCOUNT_PRESENCE(presence
))
589 PurpleAccount
*account
= purple_account_presence_get_account(
590 PURPLE_ACCOUNT_PRESENCE(presence
));
591 PurpleAccountUiOps
*ops
= purple_accounts_get_ui_ops();
593 if (purple_account_get_enabled(account
, purple_core_get_ui()))
594 purple_protocol_change_account_status(account
, old_status
, new_status
);
596 if (ops
!= NULL
&& ops
->status_changed
!= NULL
)
598 ops
->status_changed(account
, new_status
);
601 else if (PURPLE_IS_BUDDY_PRESENCE(presence
))
603 notify_buddy_status_update(purple_buddy_presence_get_buddy(
604 PURPLE_BUDDY_PRESENCE(presence
)), presence
, old_status
,
610 status_has_changed(PurpleStatus
*status
)
612 PurplePresence
*presence
;
613 PurpleStatus
*old_status
;
615 presence
= purple_status_get_presence(status
);
618 * If this status is exclusive, then we must be setting it to "active."
619 * Since we are setting it to active, we want to set the currently
620 * active status to "inactive."
622 if (purple_status_is_exclusive(status
))
624 old_status
= purple_presence_get_active_status(presence
);
625 if (old_status
!= NULL
&& (old_status
!= status
)) {
626 PurpleStatusPrivate
*priv
= purple_status_get_instance_private(old_status
);
627 priv
->active
= FALSE
;
628 g_object_notify_by_pspec(G_OBJECT(old_status
),
629 properties
[PROP_ACTIVE
]);
635 g_object_set(presence
, "active-status", status
, NULL
);
636 g_object_notify_by_pspec(G_OBJECT(status
), properties
[PROP_ACTIVE
]);
638 notify_status_update(presence
, old_status
, status
);
642 status_set_attr_boolean(PurpleStatus
*status
, const char *id
,
647 g_return_if_fail(PURPLE_IS_STATUS(status
));
648 g_return_if_fail(id
!= NULL
);
650 /* Make sure this attribute exists and is the correct type. */
651 attr_value
= purple_status_get_attr_value(status
, id
);
652 g_return_if_fail(attr_value
!= NULL
);
653 g_return_if_fail(G_VALUE_TYPE(attr_value
) == G_TYPE_BOOLEAN
);
655 g_value_set_boolean(attr_value
, value
);
659 status_set_attr_int(PurpleStatus
*status
, const char *id
, int value
)
663 g_return_if_fail(PURPLE_IS_STATUS(status
));
664 g_return_if_fail(id
!= NULL
);
666 /* Make sure this attribute exists and is the correct type. */
667 attr_value
= purple_status_get_attr_value(status
, id
);
668 g_return_if_fail(attr_value
!= NULL
);
669 g_return_if_fail(G_VALUE_TYPE(attr_value
) == G_TYPE_INT
);
671 g_value_set_int(attr_value
, value
);
675 status_set_attr_string(PurpleStatus
*status
, const char *id
,
680 g_return_if_fail(PURPLE_IS_STATUS(status
));
681 g_return_if_fail(id
!= NULL
);
683 /* Make sure this attribute exists and is the correct type. */
684 attr_value
= purple_status_get_attr_value(status
, id
);
685 /* This used to be g_return_if_fail, but it's failing a LOT, so
686 * let's generate a log error for now. */
687 /* g_return_if_fail(attr_value != NULL); */
688 if (attr_value
== NULL
) {
689 purple_debug_error("status",
690 "Attempted to set status attribute '%s' for "
691 "status '%s', which is not legal. Fix "
693 purple_status_type_get_name(purple_status_get_status_type(status
)));
696 g_return_if_fail(G_VALUE_TYPE(attr_value
) == G_TYPE_STRING
);
698 /* XXX: Check if the value has actually changed. If it has, and the status
699 * is active, should this trigger 'status_has_changed'? */
700 g_value_set_string(attr_value
, value
);
704 purple_status_set_active(PurpleStatus
*status
, gboolean active
)
706 purple_status_set_active_with_attrs_list(status
, active
, NULL
);
710 * This used to parse the va_list directly, but now it creates a GList
711 * and passes it to purple_status_set_active_with_attrs_list(). That
712 * function was created because account.c needs to pass a GList of
713 * attributes to the status API.
716 purple_status_set_active_with_attrs(PurpleStatus
*status
, gboolean active
, va_list args
)
722 while ((id
= va_arg(args
, const char *)) != NULL
)
724 attrs
= g_list_append(attrs
, (char *)id
);
725 data
= va_arg(args
, void *);
726 attrs
= g_list_append(attrs
, data
);
728 purple_status_set_active_with_attrs_list(status
, active
, attrs
);
733 purple_status_set_active_with_attrs_list(PurpleStatus
*status
, gboolean active
,
736 PurpleStatusPrivate
*priv
= NULL
;
737 gboolean changed
= FALSE
;
739 GList
*specified_attr_ids
= NULL
;
740 PurpleStatusType
*status_type
;
742 g_return_if_fail(PURPLE_IS_STATUS(status
));
744 priv
= purple_status_get_instance_private(status
);
746 if (!active
&& purple_status_is_exclusive(status
))
748 purple_debug_error("status",
749 "Cannot deactivate an exclusive status (%s).\n",
750 purple_status_get_id(status
));
754 if (priv
->active
!= active
)
759 priv
->active
= active
;
761 /* Set any attributes */
770 value
= purple_status_get_attr_value(status
, id
);
773 purple_debug_warning("status", "The attribute \"%s\" on the status \"%s\" is "
774 "not supported.\n", id
, priv
->status_type
->name
);
775 /* Skip over the data and move on to the next attribute */
780 specified_attr_ids
= g_list_prepend(specified_attr_ids
, (gpointer
)id
);
782 if (G_VALUE_TYPE(value
) == G_TYPE_STRING
)
784 const gchar
*string_data
= l
->data
;
786 if (purple_strequal(string_data
, g_value_get_string(value
)))
788 status_set_attr_string(status
, id
, string_data
);
791 else if (G_VALUE_TYPE(value
) == G_TYPE_INT
)
793 int int_data
= GPOINTER_TO_INT(l
->data
);
795 if (int_data
== g_value_get_int(value
))
797 status_set_attr_int(status
, id
, int_data
);
800 else if (G_VALUE_TYPE(value
) == G_TYPE_BOOLEAN
)
802 gboolean boolean_data
= GPOINTER_TO_INT(l
->data
);
804 if (boolean_data
== g_value_get_boolean(value
))
806 status_set_attr_boolean(status
, id
, boolean_data
);
811 /* We don't know what the data is--skip over it */
816 /* Reset any unspecified attributes to their default value */
817 status_type
= purple_status_get_status_type(status
);
818 l
= purple_status_type_get_attrs(status_type
);
820 PurpleStatusAttribute
*attr
;
825 if (!g_list_find_custom(specified_attr_ids
, attr
->id
, (GCompareFunc
)strcmp
)) {
826 GValue
*default_value
;
827 default_value
= purple_status_attribute_get_value(attr
);
828 if (G_VALUE_TYPE(default_value
) == G_TYPE_STRING
) {
829 const char *cur
= purple_status_get_attr_string(status
, attr
->id
);
830 const char *def
= g_value_get_string(default_value
);
831 if (purple_strequal(cur
, def
)) {
835 status_set_attr_string(status
, attr
->id
, def
);
836 } else if (G_VALUE_TYPE(default_value
) == G_TYPE_INT
) {
837 int cur
= purple_status_get_attr_int(status
, attr
->id
);
838 int def
= g_value_get_int(default_value
);
842 status_set_attr_int(status
, attr
->id
, def
);
843 } else if (G_VALUE_TYPE(default_value
) == G_TYPE_BOOLEAN
) {
844 gboolean cur
= purple_status_get_attr_boolean(status
, attr
->id
);
845 gboolean def
= g_value_get_boolean(default_value
);
849 status_set_attr_boolean(status
, attr
->id
, def
);
854 g_list_free(specified_attr_ids
);
858 status_has_changed(status
);
862 purple_status_get_status_type(PurpleStatus
*status
)
864 PurpleStatusPrivate
*priv
= NULL
;
866 g_return_val_if_fail(PURPLE_IS_STATUS(status
), NULL
);
868 priv
= purple_status_get_instance_private(status
);
869 return priv
->status_type
;
873 purple_status_get_presence(PurpleStatus
*status
)
875 PurpleStatusPrivate
*priv
= NULL
;
877 g_return_val_if_fail(PURPLE_IS_STATUS(status
), NULL
);
879 priv
= purple_status_get_instance_private(status
);
880 return priv
->presence
;
884 purple_status_get_id(PurpleStatus
*status
)
886 g_return_val_if_fail(PURPLE_IS_STATUS(status
), NULL
);
888 return purple_status_type_get_id(purple_status_get_status_type(status
));
892 purple_status_get_name(PurpleStatus
*status
)
894 g_return_val_if_fail(PURPLE_IS_STATUS(status
), NULL
);
896 return purple_status_type_get_name(purple_status_get_status_type(status
));
900 purple_status_is_independent(PurpleStatus
*status
)
902 g_return_val_if_fail(PURPLE_IS_STATUS(status
), FALSE
);
904 return purple_status_type_is_independent(purple_status_get_status_type(status
));
908 purple_status_is_exclusive(PurpleStatus
*status
)
910 g_return_val_if_fail(PURPLE_IS_STATUS(status
), FALSE
);
912 return purple_status_type_is_exclusive(purple_status_get_status_type(status
));
916 purple_status_is_available(PurpleStatus
*status
)
918 g_return_val_if_fail(PURPLE_IS_STATUS(status
), FALSE
);
920 return purple_status_type_is_available(purple_status_get_status_type(status
));
924 purple_status_is_active(PurpleStatus
*status
)
926 PurpleStatusPrivate
*priv
= NULL
;
928 g_return_val_if_fail(PURPLE_IS_STATUS(status
), FALSE
);
930 priv
= purple_status_get_instance_private(status
);
935 purple_status_is_online(PurpleStatus
*status
)
937 PurpleStatusPrimitive primitive
;
939 g_return_val_if_fail(PURPLE_IS_STATUS(status
), FALSE
);
941 primitive
= purple_status_type_get_primitive(purple_status_get_status_type(status
));
943 return (primitive
!= PURPLE_STATUS_UNSET
&&
944 primitive
!= PURPLE_STATUS_OFFLINE
);
948 purple_status_get_attr_value(PurpleStatus
*status
, const char *id
)
950 PurpleStatusPrivate
*priv
= NULL
;
952 g_return_val_if_fail(PURPLE_IS_STATUS(status
), NULL
);
953 g_return_val_if_fail(id
!= NULL
, NULL
);
955 priv
= purple_status_get_instance_private(status
);
956 return (GValue
*)g_hash_table_lookup(priv
->attr_values
, id
);
960 purple_status_get_attr_boolean(PurpleStatus
*status
, const char *id
)
964 g_return_val_if_fail(PURPLE_IS_STATUS(status
), FALSE
);
965 g_return_val_if_fail(id
!= NULL
, FALSE
);
967 if ((value
= purple_status_get_attr_value(status
, id
)) == NULL
)
970 g_return_val_if_fail(G_VALUE_TYPE(value
) == G_TYPE_BOOLEAN
, FALSE
);
972 return g_value_get_boolean(value
);
976 purple_status_get_attr_int(PurpleStatus
*status
, const char *id
)
980 g_return_val_if_fail(PURPLE_IS_STATUS(status
), 0);
981 g_return_val_if_fail(id
!= NULL
, 0);
983 if ((value
= purple_status_get_attr_value(status
, id
)) == NULL
)
986 g_return_val_if_fail(G_VALUE_TYPE(value
) == G_TYPE_INT
, 0);
988 return g_value_get_int(value
);
992 purple_status_get_attr_string(PurpleStatus
*status
, const char *id
)
996 g_return_val_if_fail(PURPLE_IS_STATUS(status
), NULL
);
997 g_return_val_if_fail(id
!= NULL
, NULL
);
999 if ((value
= purple_status_get_attr_value(status
, id
)) == NULL
)
1002 g_return_val_if_fail(G_VALUE_TYPE(value
) == G_TYPE_STRING
, NULL
);
1004 return g_value_get_string(value
);
1008 purple_status_compare(PurpleStatus
*status1
, PurpleStatus
*status2
)
1010 PurpleStatusType
*type1
, *type2
;
1011 int score1
= 0, score2
= 0;
1013 if ((status1
== NULL
&& status2
== NULL
) ||
1014 (status1
== status2
))
1018 else if (status1
== NULL
)
1020 else if (status2
== NULL
)
1023 type1
= purple_status_get_status_type(status1
);
1024 type2
= purple_status_get_status_type(status2
);
1026 if (purple_status_is_active(status1
))
1027 score1
= primitive_scores
[purple_status_type_get_primitive(type1
)];
1029 if (purple_status_is_active(status2
))
1030 score2
= primitive_scores
[purple_status_type_get_primitive(type2
)];
1032 if (score1
> score2
)
1034 else if (score1
< score2
)
1041 /**************************************************************************
1042 * GBoxed code for PurpleStatusType
1043 **************************************************************************/
1044 static PurpleStatusType
*
1045 purple_status_type_ref(PurpleStatusType
*status_type
)
1047 g_return_val_if_fail(status_type
!= NULL
, NULL
);
1049 status_type
->box_count
++;
1055 purple_status_type_unref(PurpleStatusType
*status_type
)
1057 g_return_if_fail(status_type
!= NULL
);
1058 g_return_if_fail(status_type
->box_count
>= 0);
1060 if (!status_type
->box_count
--)
1061 purple_status_type_destroy(status_type
);
1065 purple_status_type_get_type(void)
1067 static GType type
= 0;
1070 type
= g_boxed_type_register_static("PurpleStatusType",
1071 (GBoxedCopyFunc
)purple_status_type_ref
,
1072 (GBoxedFreeFunc
)purple_status_type_unref
);
1078 /**************************************************************************
1079 * GBoxed code for PurpleStatusAttribute
1080 **************************************************************************/
1081 static PurpleStatusAttribute
*
1082 purple_status_attribute_copy(PurpleStatusAttribute
*status_attr
)
1084 g_return_val_if_fail(status_attr
!= NULL
, NULL
);
1086 return purple_status_attribute_new(status_attr
->id
,
1088 purple_value_dup(status_attr
->value_type
));
1092 purple_status_attribute_get_type(void)
1094 static GType type
= 0;
1097 type
= g_boxed_type_register_static("PurpleStatusAttribute",
1098 (GBoxedCopyFunc
)purple_status_attribute_copy
,
1099 (GBoxedFreeFunc
)purple_status_attribute_destroy
);
1105 /**************************************************************************
1106 * GBoxed code for PurpleMood
1107 **************************************************************************/
1109 purple_mood_copy(PurpleMood
*mood
)
1111 PurpleMood
*mood_copy
;
1113 g_return_val_if_fail(mood
!= NULL
, NULL
);
1115 mood_copy
= g_new(PurpleMood
, 1);
1117 mood_copy
->mood
= g_strdup(mood
->mood
);
1118 mood_copy
->description
= g_strdup(mood
->description
);
1124 purple_mood_free(PurpleMood
*mood
)
1126 g_free((gchar
*)mood
->mood
);
1127 g_free((gchar
*)mood
->description
);
1133 purple_mood_get_type(void)
1135 static GType type
= 0;
1138 type
= g_boxed_type_register_static("PurpleMood",
1139 (GBoxedCopyFunc
)purple_mood_copy
,
1140 (GBoxedFreeFunc
)purple_mood_free
);
1147 /**************************************************************************
1149 **************************************************************************/
1151 /* Set method for GObject properties */
1153 purple_status_set_property(GObject
*obj
, guint param_id
, const GValue
*value
,
1156 PurpleStatus
*status
= PURPLE_STATUS(obj
);
1157 PurpleStatusPrivate
*priv
= purple_status_get_instance_private(status
);
1160 case PROP_STATUS_TYPE
:
1161 priv
->status_type
= g_value_get_pointer(value
);
1164 priv
->presence
= g_value_get_object(value
);
1167 purple_status_set_active(status
, g_value_get_boolean(value
));
1170 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1175 /* Get method for GObject properties */
1177 purple_status_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
1180 PurpleStatus
*status
= PURPLE_STATUS(obj
);
1183 case PROP_STATUS_TYPE
:
1184 g_value_set_pointer(value
, purple_status_get_status_type(status
));
1187 g_value_set_object(value
, purple_status_get_presence(status
));
1190 g_value_set_boolean(value
, purple_status_is_active(status
));
1193 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
1198 /* GObject initialization function */
1200 purple_status_init(PurpleStatus
*status
)
1202 PurpleStatusPrivate
*priv
= purple_status_get_instance_private(status
);
1205 g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
,
1206 (GDestroyNotify
)purple_value_free
);
1209 /* Called when done constructing */
1211 purple_status_constructed(GObject
*object
)
1214 PurpleStatusPrivate
*priv
= purple_status_get_instance_private(PURPLE_STATUS(object
));
1216 G_OBJECT_CLASS(purple_status_parent_class
)->constructed(object
);
1218 for (l
= purple_status_type_get_attrs(priv
->status_type
); l
!= NULL
; l
= l
->next
)
1220 PurpleStatusAttribute
*attr
= (PurpleStatusAttribute
*)l
->data
;
1221 GValue
*value
= purple_status_attribute_get_value(attr
);
1222 GValue
*new_value
= purple_value_dup(value
);
1224 g_hash_table_insert(priv
->attr_values
,
1225 (char *)purple_status_attribute_get_id(attr
),
1231 * GObject finalize function
1232 * TODO: If the PurpleStatus is in a PurplePresence, then
1233 * remove it from the PurplePresence?
1236 purple_status_finalize(GObject
*obj
)
1238 PurpleStatusPrivate
*priv
= purple_status_get_instance_private(PURPLE_STATUS(obj
));
1239 g_hash_table_destroy(priv
->attr_values
);
1241 G_OBJECT_CLASS(purple_status_parent_class
)->finalize(obj
);
1244 /* Class initializer function */
1246 purple_status_class_init(PurpleStatusClass
*klass
)
1248 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
1250 obj_class
->finalize
= purple_status_finalize
;
1251 obj_class
->constructed
= purple_status_constructed
;
1253 /* Setup properties */
1254 obj_class
->get_property
= purple_status_get_property
;
1255 obj_class
->set_property
= purple_status_set_property
;
1257 properties
[PROP_STATUS_TYPE
] = g_param_spec_pointer("status-type",
1259 "The PurpleStatusType of the status.",
1260 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
1261 G_PARAM_STATIC_STRINGS
);
1263 properties
[PROP_PRESENCE
] = g_param_spec_object("presence", "Presence",
1264 "The presence that the status belongs to.",
1265 PURPLE_TYPE_PRESENCE
,
1266 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
|
1267 G_PARAM_STATIC_STRINGS
);
1269 properties
[PROP_ACTIVE
] = g_param_spec_boolean("active", "Active",
1270 "Whether the status is active or not.", FALSE
,
1271 G_PARAM_READWRITE
| G_PARAM_STATIC_STRINGS
);
1273 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
1277 purple_status_new(PurpleStatusType
*status_type
, PurplePresence
*presence
)
1279 g_return_val_if_fail(status_type
!= NULL
, NULL
);
1280 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence
), NULL
);
1282 return g_object_new(PURPLE_TYPE_STATUS
,
1283 "status-type", status_type
,
1284 "presence", presence
,
1289 /**************************************************************************
1291 **************************************************************************/
1293 score_pref_changed_cb(const char *name
, PurplePrefType type
,
1294 gconstpointer value
, gpointer data
)
1296 int index
= GPOINTER_TO_INT(data
);
1298 primitive_scores
[index
] = GPOINTER_TO_INT(value
);
1302 purple_statuses_get_handle(void) {
1309 purple_statuses_init(void)
1311 void *handle
= purple_statuses_get_handle();
1313 purple_prefs_add_none("/purple/status");
1314 purple_prefs_add_none("/purple/status/scores");
1316 purple_prefs_add_int("/purple/status/scores/offline",
1317 primitive_scores
[PURPLE_STATUS_OFFLINE
]);
1318 purple_prefs_add_int("/purple/status/scores/available",
1319 primitive_scores
[PURPLE_STATUS_AVAILABLE
]);
1320 purple_prefs_add_int("/purple/status/scores/invisible",
1321 primitive_scores
[PURPLE_STATUS_INVISIBLE
]);
1322 purple_prefs_add_int("/purple/status/scores/away",
1323 primitive_scores
[PURPLE_STATUS_AWAY
]);
1324 purple_prefs_add_int("/purple/status/scores/extended_away",
1325 primitive_scores
[PURPLE_STATUS_EXTENDED_AWAY
]);
1326 purple_prefs_add_int("/purple/status/scores/idle",
1327 primitive_scores
[SCORE_IDLE
]);
1328 purple_prefs_add_int("/purple/status/scores/idle_time",
1329 primitive_scores
[SCORE_IDLE_TIME
]);
1330 purple_prefs_add_int("/purple/status/scores/offline_msg",
1331 primitive_scores
[SCORE_OFFLINE_MESSAGE
]);
1333 purple_prefs_connect_callback(handle
, "/purple/status/scores/offline",
1334 score_pref_changed_cb
,
1335 GINT_TO_POINTER(PURPLE_STATUS_OFFLINE
));
1336 purple_prefs_connect_callback(handle
, "/purple/status/scores/available",
1337 score_pref_changed_cb
,
1338 GINT_TO_POINTER(PURPLE_STATUS_AVAILABLE
));
1339 purple_prefs_connect_callback(handle
, "/purple/status/scores/invisible",
1340 score_pref_changed_cb
,
1341 GINT_TO_POINTER(PURPLE_STATUS_INVISIBLE
));
1342 purple_prefs_connect_callback(handle
, "/purple/status/scores/away",
1343 score_pref_changed_cb
,
1344 GINT_TO_POINTER(PURPLE_STATUS_AWAY
));
1345 purple_prefs_connect_callback(handle
, "/purple/status/scores/extended_away",
1346 score_pref_changed_cb
,
1347 GINT_TO_POINTER(PURPLE_STATUS_EXTENDED_AWAY
));
1348 purple_prefs_connect_callback(handle
, "/purple/status/scores/idle",
1349 score_pref_changed_cb
,
1350 GINT_TO_POINTER(SCORE_IDLE
));
1351 purple_prefs_connect_callback(handle
, "/purple/status/scores/idle_time",
1352 score_pref_changed_cb
,
1353 GINT_TO_POINTER(SCORE_IDLE_TIME
));
1354 purple_prefs_connect_callback(handle
, "/purple/status/scores/offline_msg",
1355 score_pref_changed_cb
,
1356 GINT_TO_POINTER(SCORE_OFFLINE_MESSAGE
));
1358 purple_prefs_trigger_callback("/purple/status/scores/offline");
1359 purple_prefs_trigger_callback("/purple/status/scores/available");
1360 purple_prefs_trigger_callback("/purple/status/scores/invisible");
1361 purple_prefs_trigger_callback("/purple/status/scores/away");
1362 purple_prefs_trigger_callback("/purple/status/scores/extended_away");
1363 purple_prefs_trigger_callback("/purple/status/scores/idle");
1364 purple_prefs_trigger_callback("/purple/status/scores/idle_time");
1365 purple_prefs_trigger_callback("/purple/status/scores/offline_msg");
1369 purple_statuses_uninit(void)
1371 purple_prefs_disconnect_by_handle(purple_prefs_get_handle());