Merged pidgin/main into default
[pidgin-git.git] / libpurple / presence.c
blob3af91b4ceb700617a98332b9003bc8b15ab95348
1 /* purple
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
5 * source distribution.
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
21 #include "internal.h"
22 #include "glibcompat.h"
23 #include "debug.h"
24 #include "dbus-maybe.h"
25 #include "presence.h"
27 #define PURPLE_PRESENCE_GET_PRIVATE(obj) \
28 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_PRESENCE, PurplePresencePrivate))
30 /** @copydoc _PurplePresencePrivate */
31 typedef struct _PurplePresencePrivate PurplePresencePrivate;
33 #define PURPLE_ACCOUNT_PRESENCE_GET_PRIVATE(obj) \
34 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_ACCOUNT_PRESENCE, PurpleAccountPresencePrivate))
36 /** @copydoc _PurpleAccountPresencePrivate */
37 typedef struct _PurpleAccountPresencePrivate PurpleAccountPresencePrivate;
39 #define PURPLE_BUDDY_PRESENCE_GET_PRIVATE(obj) \
40 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_BUDDY_PRESENCE, PurpleBuddyPresencePrivate))
42 /** @copydoc _PurpleBuddyPresencePrivate */
43 typedef struct _PurpleBuddyPresencePrivate PurpleBuddyPresencePrivate;
45 /** Private data for a presence */
46 struct _PurplePresencePrivate
48 gboolean idle;
49 time_t idle_time;
50 time_t login_time;
52 GList *statuses;
53 GHashTable *status_table;
55 PurpleStatus *active_status;
58 /* Presence property enums */
59 enum
61 PRES_PROP_0,
62 PRES_PROP_IDLE,
63 PRES_PROP_IDLE_TIME,
64 PRES_PROP_LOGIN_TIME,
65 PRES_PROP_STATUSES,
66 PRES_PROP_ACTIVE_STATUS,
67 PRES_PROP_LAST
70 /** Private data for an account presence */
71 struct _PurpleAccountPresencePrivate
73 PurpleAccount *account;
76 /* Account presence property enums */
77 enum
79 ACPRES_PROP_0,
80 ACPRES_PROP_ACCOUNT,
81 ACPRES_PROP_LAST
84 /** Private data for a buddy presence */
85 struct _PurpleBuddyPresencePrivate
87 PurpleBuddy *buddy;
90 /* Buddy presence property enums */
91 enum
93 BUDPRES_PROP_0,
94 BUDPRES_PROP_BUDDY,
95 BUDPRES_PROP_LAST
98 static GObjectClass *parent_class;
99 static PurplePresenceClass *presence_class;
101 static GParamSpec *properties[PRES_PROP_LAST];
102 static GParamSpec *ap_properties[ACPRES_PROP_LAST];
103 static GParamSpec *bp_properties[BUDPRES_PROP_LAST];
105 /**************************************************************************
106 * PurplePresence API
107 **************************************************************************/
109 void
110 purple_presence_set_status_active(PurplePresence *presence, const char *status_id,
111 gboolean active)
113 PurpleStatus *status;
115 g_return_if_fail(PURPLE_IS_PRESENCE(presence));
116 g_return_if_fail(status_id != NULL);
118 status = purple_presence_get_status(presence, status_id);
120 g_return_if_fail(PURPLE_IS_STATUS(status));
121 /* TODO: Should we do the following? */
122 /* g_return_if_fail(active == status->active); */
124 if (purple_status_is_exclusive(status))
126 if (!active)
128 purple_debug_warning("presence",
129 "Attempted to set a non-independent status "
130 "(%s) inactive. Only independent statuses "
131 "can be specifically marked inactive.",
132 status_id);
133 return;
137 purple_status_set_active(status, active);
140 void
141 purple_presence_switch_status(PurplePresence *presence, const char *status_id)
143 purple_presence_set_status_active(presence, status_id, TRUE);
146 void
147 purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time)
149 gboolean old_idle;
150 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
151 PurplePresenceClass *klass = PURPLE_PRESENCE_GET_CLASS(presence);
152 GObject *obj;
154 g_return_if_fail(priv != NULL);
156 if (priv->idle == idle && priv->idle_time == idle_time)
157 return;
159 old_idle = priv->idle;
160 priv->idle = idle;
161 priv->idle_time = (idle ? idle_time : 0);
163 obj = G_OBJECT(presence);
164 g_object_freeze_notify(obj);
165 g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE]);
166 g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE_TIME]);
167 g_object_thaw_notify(obj);
169 if (klass->update_idle)
170 klass->update_idle(presence, old_idle);
173 void
174 purple_presence_set_login_time(PurplePresence *presence, time_t login_time)
176 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
178 g_return_if_fail(priv != NULL);
180 if (priv->login_time == login_time)
181 return;
183 priv->login_time = login_time;
185 g_object_notify_by_pspec(G_OBJECT(presence),
186 properties[PRES_PROP_LOGIN_TIME]);
189 GList *
190 purple_presence_get_statuses(const PurplePresence *presence)
192 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
194 g_return_val_if_fail(priv != NULL, NULL);
196 return priv->statuses;
199 PurpleStatus *
200 purple_presence_get_status(const PurplePresence *presence, const char *status_id)
202 PurpleStatus *status;
203 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
204 GList *l = NULL;
206 g_return_val_if_fail(priv != NULL, NULL);
207 g_return_val_if_fail(status_id != NULL, NULL);
209 /* What's the purpose of this hash table? */
210 status = (PurpleStatus *)g_hash_table_lookup(priv->status_table,
211 status_id);
213 if (status == NULL) {
214 for (l = purple_presence_get_statuses(presence);
215 l != NULL && status == NULL; l = l->next)
217 PurpleStatus *temp_status = l->data;
219 if (purple_strequal(status_id, purple_status_get_id(temp_status)))
220 status = temp_status;
223 if (status != NULL)
224 g_hash_table_insert(priv->status_table,
225 g_strdup(purple_status_get_id(status)), status);
228 return status;
231 PurpleStatus *
232 purple_presence_get_active_status(const PurplePresence *presence)
234 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
236 g_return_val_if_fail(priv != NULL, NULL);
238 return priv->active_status;
241 gboolean
242 purple_presence_is_available(const PurplePresence *presence)
244 PurpleStatus *status;
246 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
248 status = purple_presence_get_active_status(presence);
250 return ((status != NULL && purple_status_is_available(status)) &&
251 !purple_presence_is_idle(presence));
254 gboolean
255 purple_presence_is_online(const PurplePresence *presence)
257 PurpleStatus *status;
259 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
261 if ((status = purple_presence_get_active_status(presence)) == NULL)
262 return FALSE;
264 return purple_status_is_online(status);
267 gboolean
268 purple_presence_is_status_active(const PurplePresence *presence,
269 const char *status_id)
271 PurpleStatus *status;
273 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
274 g_return_val_if_fail(status_id != NULL, FALSE);
276 status = purple_presence_get_status(presence, status_id);
278 return (status != NULL && purple_status_is_active(status));
281 gboolean
282 purple_presence_is_status_primitive_active(const PurplePresence *presence,
283 PurpleStatusPrimitive primitive)
285 GList *l;
287 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
288 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, FALSE);
290 for (l = purple_presence_get_statuses(presence);
291 l != NULL; l = l->next)
293 PurpleStatus *temp_status = l->data;
294 PurpleStatusType *type = purple_status_get_status_type(temp_status);
296 if (purple_status_type_get_primitive(type) == primitive &&
297 purple_status_is_active(temp_status))
298 return TRUE;
300 return FALSE;
303 gboolean
304 purple_presence_is_idle(const PurplePresence *presence)
306 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
308 g_return_val_if_fail(priv != NULL, FALSE);
310 return purple_presence_is_online(presence) && priv->idle;
313 time_t
314 purple_presence_get_idle_time(const PurplePresence *presence)
316 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
318 g_return_val_if_fail(priv != NULL, 0);
320 return priv->idle_time;
323 time_t
324 purple_presence_get_login_time(const PurplePresence *presence)
326 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
328 g_return_val_if_fail(priv != NULL, 0);
330 return purple_presence_is_online(presence) ? priv->login_time : 0;
333 /**************************************************************************
334 * GObject code for PurplePresence
335 **************************************************************************/
337 /* Set method for GObject properties */
338 static void
339 purple_presence_set_property(GObject *obj, guint param_id, const GValue *value,
340 GParamSpec *pspec)
342 PurplePresence *presence = PURPLE_PRESENCE(obj);
343 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(presence);
345 switch (param_id) {
346 case PRES_PROP_IDLE:
347 purple_presence_set_idle(presence, g_value_get_boolean(value), 0);
348 break;
349 case PRES_PROP_IDLE_TIME:
350 #if SIZEOF_TIME_T == 4
351 purple_presence_set_idle(presence, TRUE, g_value_get_int(value));
352 #elif SIZEOF_TIME_T == 8
353 purple_presence_set_idle(presence, TRUE, g_value_get_int64(value));
354 #else
355 #error Unknown size of time_t
356 #endif
357 break;
358 case PRES_PROP_LOGIN_TIME:
359 #if SIZEOF_TIME_T == 4
360 purple_presence_set_login_time(presence, g_value_get_int(value));
361 #elif SIZEOF_TIME_T == 8
362 purple_presence_set_login_time(presence, g_value_get_int64(value));
363 #else
364 #error Unknown size of time_t
365 #endif
366 break;
367 case PRES_PROP_ACTIVE_STATUS:
368 priv->active_status = g_value_get_object(value);
369 break;
370 default:
371 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
372 break;
376 /* Get method for GObject properties */
377 static void
378 purple_presence_get_property(GObject *obj, guint param_id, GValue *value,
379 GParamSpec *pspec)
381 PurplePresence *presence = PURPLE_PRESENCE(obj);
383 switch (param_id) {
384 case PRES_PROP_IDLE:
385 g_value_set_boolean(value, purple_presence_is_idle(presence));
386 break;
387 case PRES_PROP_IDLE_TIME:
388 #if SIZEOF_TIME_T == 4
389 g_value_set_int(value, purple_presence_get_idle_time(presence));
390 #elif SIZEOF_TIME_T == 8
391 g_value_set_int64(value, purple_presence_get_idle_time(presence));
392 #else
393 #error Unknown size of time_t
394 #endif
395 break;
396 case PRES_PROP_LOGIN_TIME:
397 #if SIZEOF_TIME_T == 4
398 g_value_set_int(value, purple_presence_get_login_time(presence));
399 #elif SIZEOF_TIME_T == 8
400 g_value_set_int64(value, purple_presence_get_login_time(presence));
401 #else
402 #error Unknown size of time_t
403 #endif
404 break;
405 case PRES_PROP_STATUSES:
406 g_value_set_pointer(value, purple_presence_get_statuses(presence));
407 break;
408 case PRES_PROP_ACTIVE_STATUS:
409 g_value_set_object(value, purple_presence_get_active_status(presence));
410 break;
411 default:
412 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
413 break;
417 /* GObject initialization function */
418 static void
419 purple_presence_init(GTypeInstance *instance, gpointer klass)
421 PURPLE_DBUS_REGISTER_POINTER(PURPLE_PRESENCE(instance), PurplePresence);
423 PURPLE_PRESENCE_GET_PRIVATE(instance)->status_table =
424 g_hash_table_new_full(g_str_hash, g_str_equal,
425 g_free, NULL);
428 /* GObject dispose function */
429 static void
430 purple_presence_dispose(GObject *object)
432 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(object);
434 if (priv->statuses) {
435 g_list_foreach(priv->statuses, (GFunc)g_object_unref, NULL);
436 g_list_free(priv->statuses);
437 priv->statuses = NULL;
440 parent_class->dispose(object);
443 /* GObject finalize function */
444 static void
445 purple_presence_finalize(GObject *object)
447 PurplePresencePrivate *priv = PURPLE_PRESENCE_GET_PRIVATE(object);
449 g_hash_table_destroy(priv->status_table);
451 PURPLE_DBUS_UNREGISTER_POINTER(object);
453 parent_class->finalize(object);
456 /* Class initializer function */
457 static void purple_presence_class_init(PurplePresenceClass *klass)
459 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
461 parent_class = g_type_class_peek_parent(klass);
463 obj_class->dispose = purple_presence_dispose;
464 obj_class->finalize = purple_presence_finalize;
466 /* Setup properties */
467 obj_class->get_property = purple_presence_get_property;
468 obj_class->set_property = purple_presence_set_property;
470 g_type_class_add_private(klass, sizeof(PurplePresencePrivate));
472 properties[PRES_PROP_IDLE] = g_param_spec_boolean("idle", "Idle",
473 "Whether the presence is in idle state.", FALSE,
474 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
476 properties[PRES_PROP_IDLE_TIME] =
477 #if SIZEOF_TIME_T == 4
478 g_param_spec_int
479 #elif SIZEOF_TIME_T == 8
480 g_param_spec_int64
481 #else
482 #error Unknown size of time_t
483 #endif
484 ("idle-time", "Idle time",
485 "The idle time of the presence",
486 #if SIZEOF_TIME_T == 4
487 G_MININT, G_MAXINT, 0,
488 #elif SIZEOF_TIME_T == 8
489 G_MININT64, G_MAXINT64, 0,
490 #else
491 #error Unknown size of time_t
492 #endif
493 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
495 properties[PRES_PROP_LOGIN_TIME] =
496 #if SIZEOF_TIME_T == 4
497 g_param_spec_int
498 #elif SIZEOF_TIME_T == 8
499 g_param_spec_int64
500 #else
501 #error Unknown size of time_t
502 #endif
503 ("login-time", "Login time",
504 "The login time of the presence.",
505 #if SIZEOF_TIME_T == 4
506 G_MININT, G_MAXINT, 0,
507 #elif SIZEOF_TIME_T == 8
508 G_MININT64, G_MAXINT64, 0,
509 #else
510 #error Unknown size of time_t
511 #endif
512 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
514 properties[PRES_PROP_STATUSES] = g_param_spec_pointer("statuses",
515 "Statuses",
516 "The list of statuses in the presence.",
517 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
519 properties[PRES_PROP_ACTIVE_STATUS] = g_param_spec_object("active-status",
520 "Active status",
521 "The active status for the presence.", PURPLE_TYPE_STATUS,
522 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
524 g_object_class_install_properties(obj_class, PRES_PROP_LAST, properties);
527 GType
528 purple_presence_get_type(void)
530 static GType type = 0;
532 if(type == 0) {
533 static const GTypeInfo info = {
534 sizeof(PurplePresenceClass),
535 NULL,
536 NULL,
537 (GClassInitFunc)purple_presence_class_init,
538 NULL,
539 NULL,
540 sizeof(PurplePresence),
542 (GInstanceInitFunc)purple_presence_init,
543 NULL,
546 type = g_type_register_static(G_TYPE_OBJECT, "PurplePresence",
547 &info, G_TYPE_FLAG_ABSTRACT);
550 return type;
553 /**************************************************************************
554 * PurpleAccountPresence API
555 **************************************************************************/
556 static void
557 purple_account_presence_update_idle(PurplePresence *presence, gboolean old_idle)
559 PurpleAccount *account;
560 PurpleConnection *gc = NULL;
561 PurpleProtocol *protocol = NULL;
562 gboolean idle = purple_presence_is_idle(presence);
563 time_t idle_time = purple_presence_get_idle_time(presence);
564 time_t current_time = time(NULL);
566 account = purple_account_presence_get_account(PURPLE_ACCOUNT_PRESENCE(presence));
568 if (purple_prefs_get_bool("/purple/logging/log_system"))
570 PurpleLog *log = purple_account_get_log(account, FALSE);
572 if (log != NULL)
574 char *msg, *tmp;
575 GDateTime *dt;
577 if (idle) {
578 tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
579 dt = g_date_time_new_from_unix_local(idle_time);
580 } else {
581 tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
582 dt = g_date_time_new_now_utc();
585 msg = g_markup_escape_text(tmp, -1);
586 g_free(tmp);
587 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
588 purple_account_get_username(account),
589 dt, msg);
590 g_date_time_unref(dt);
591 g_free(msg);
595 gc = purple_account_get_connection(account);
597 if(PURPLE_CONNECTION_IS_CONNECTED(gc))
598 protocol = purple_connection_get_protocol(gc);
600 if (protocol)
601 purple_protocol_server_iface_set_idle(protocol, gc, (idle ? (current_time - idle_time) : 0));
604 PurpleAccount *
605 purple_account_presence_get_account(const PurpleAccountPresence *presence)
607 PurpleAccountPresencePrivate *priv = PURPLE_ACCOUNT_PRESENCE_GET_PRIVATE(presence);
609 g_return_val_if_fail(priv != NULL, NULL);
611 return priv->account;
614 static int
615 purple_buddy_presence_compute_score(const PurpleBuddyPresence *buddy_presence)
617 GList *l;
618 int score = 0;
619 PurplePresence *presence = PURPLE_PRESENCE(buddy_presence);
620 PurpleBuddy *b = purple_buddy_presence_get_buddy(buddy_presence);
621 int *primitive_scores = _purple_statuses_get_primitive_scores();
622 int offline_score = purple_prefs_get_int("/purple/status/scores/offline_msg");
623 int idle_score = purple_prefs_get_int("/purple/status/scores/idle");
625 for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) {
626 PurpleStatus *status = (PurpleStatus *)l->data;
627 PurpleStatusType *type = purple_status_get_status_type(status);
629 if (purple_status_is_active(status)) {
630 score += primitive_scores[purple_status_type_get_primitive(type)];
631 if (!purple_status_is_online(status)) {
632 if (b && purple_account_supports_offline_message(purple_buddy_get_account(b), b))
633 score += offline_score;
637 score += purple_account_get_int(purple_buddy_get_account(b), "score", 0);
638 if (purple_presence_is_idle(presence))
639 score += idle_score;
640 return score;
643 gint
644 purple_buddy_presence_compare(const PurpleBuddyPresence *buddy_presence1,
645 const PurpleBuddyPresence *buddy_presence2)
647 PurplePresence *presence1 = PURPLE_PRESENCE(buddy_presence1);
648 PurplePresence *presence2 = PURPLE_PRESENCE(buddy_presence2);
649 time_t idle_time_1, idle_time_2;
650 int score1 = 0, score2 = 0;
651 int idle_time_score = purple_prefs_get_int("/purple/status/scores/idle_time");
653 if (presence1 == presence2)
654 return 0;
655 else if (presence1 == NULL)
656 return 1;
657 else if (presence2 == NULL)
658 return -1;
660 if (purple_presence_is_online(presence1) &&
661 !purple_presence_is_online(presence2))
662 return -1;
663 else if (purple_presence_is_online(presence2) &&
664 !purple_presence_is_online(presence1))
665 return 1;
667 /* Compute the score of the first set of statuses. */
668 score1 = purple_buddy_presence_compute_score(buddy_presence1);
670 /* Compute the score of the second set of statuses. */
671 score2 = purple_buddy_presence_compute_score(buddy_presence2);
673 idle_time_1 = time(NULL) - purple_presence_get_idle_time(presence1);
674 idle_time_2 = time(NULL) - purple_presence_get_idle_time(presence2);
676 if (idle_time_1 > idle_time_2)
677 score1 += idle_time_score;
678 else if (idle_time_1 < idle_time_2)
679 score2 += idle_time_score;
681 if (score1 < score2)
682 return 1;
683 else if (score1 > score2)
684 return -1;
686 return 0;
689 /**************************************************************************
690 * GObject code for PurpleAccountPresence
691 **************************************************************************/
693 /* Set method for GObject properties */
694 static void
695 purple_account_presence_set_property(GObject *obj, guint param_id, const GValue *value,
696 GParamSpec *pspec)
698 PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj);
699 PurpleAccountPresencePrivate *priv =
700 PURPLE_ACCOUNT_PRESENCE_GET_PRIVATE(account_presence);
702 switch (param_id) {
703 case ACPRES_PROP_ACCOUNT:
704 priv->account = g_value_get_object(value);
705 break;
706 default:
707 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
708 break;
712 /* Get method for GObject properties */
713 static void
714 purple_account_presence_get_property(GObject *obj, guint param_id, GValue *value,
715 GParamSpec *pspec)
717 PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj);
719 switch (param_id) {
720 case ACPRES_PROP_ACCOUNT:
721 g_value_set_object(value,
722 purple_account_presence_get_account(account_presence));
723 break;
724 default:
725 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
726 break;
730 /* Called when done constructing */
731 static void
732 purple_account_presence_constructed(GObject *object)
734 PurplePresence *presence = PURPLE_PRESENCE(object);
735 PurpleAccountPresencePrivate *priv = PURPLE_ACCOUNT_PRESENCE_GET_PRIVATE(presence);
737 G_OBJECT_CLASS(presence_class)->constructed(object);
739 PURPLE_PRESENCE_GET_PRIVATE(presence)->statuses =
740 purple_protocol_get_statuses(priv->account, presence);
743 /* Class initializer function */
744 static void purple_account_presence_class_init(PurpleAccountPresenceClass *klass)
746 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
748 PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_account_presence_update_idle;
750 presence_class = g_type_class_peek_parent(klass);
752 obj_class->constructed = purple_account_presence_constructed;
754 /* Setup properties */
755 obj_class->get_property = purple_account_presence_get_property;
756 obj_class->set_property = purple_account_presence_set_property;
758 g_type_class_add_private(klass, sizeof(PurpleAccountPresencePrivate));
760 ap_properties[ACPRES_PROP_ACCOUNT] = g_param_spec_object("account",
761 "Account",
762 "The account that this presence is of.", PURPLE_TYPE_ACCOUNT,
763 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
764 G_PARAM_STATIC_STRINGS);
766 g_object_class_install_properties(obj_class, ACPRES_PROP_LAST,
767 ap_properties);
770 GType
771 purple_account_presence_get_type(void)
773 static GType type = 0;
775 if(type == 0) {
776 static const GTypeInfo info = {
777 sizeof(PurpleAccountPresenceClass),
778 NULL,
779 NULL,
780 (GClassInitFunc)purple_account_presence_class_init,
781 NULL,
782 NULL,
783 sizeof(PurpleAccountPresence),
785 NULL,
786 NULL,
789 type = g_type_register_static(PURPLE_TYPE_PRESENCE,
790 "PurpleAccountPresence",
791 &info, 0);
794 return type;
797 PurpleAccountPresence *
798 purple_account_presence_new(PurpleAccount *account)
800 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
802 return g_object_new(PURPLE_TYPE_ACCOUNT_PRESENCE,
803 "account", account,
804 NULL);
807 /**************************************************************************
808 * PurpleBuddyPresence API
809 **************************************************************************/
810 static void
811 purple_buddy_presence_update_idle(PurplePresence *presence, gboolean old_idle)
813 PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(presence));
814 GDateTime *current_time = g_date_time_new_now_utc();
815 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
816 PurpleAccount *account = purple_buddy_get_account(buddy);
817 gboolean idle = purple_presence_is_idle(presence);
819 if (!old_idle && idle)
821 if (purple_prefs_get_bool("/purple/logging/log_system"))
823 PurpleLog *log = purple_account_get_log(account, FALSE);
825 if (log != NULL)
827 char *tmp, *tmp2;
828 tmp = g_strdup_printf(_("%s became idle"),
829 purple_buddy_get_alias(buddy));
830 tmp2 = g_markup_escape_text(tmp, -1);
831 g_free(tmp);
833 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
834 purple_buddy_get_alias(buddy),
835 current_time, tmp2);
836 g_free(tmp2);
840 else if (old_idle && !idle)
842 if (purple_prefs_get_bool("/purple/logging/log_system"))
844 PurpleLog *log = purple_account_get_log(account, FALSE);
846 if (log != NULL)
848 char *tmp, *tmp2;
849 tmp = g_strdup_printf(_("%s became unidle"),
850 purple_buddy_get_alias(buddy));
851 tmp2 = g_markup_escape_text(tmp, -1);
852 g_free(tmp);
854 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
855 purple_buddy_get_alias(buddy),
856 current_time, tmp2);
857 g_free(tmp2);
862 if (old_idle != idle)
863 purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
864 old_idle, idle);
866 purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
868 /* Should this be done here? It'd perhaps make more sense to
869 * connect to buddy-[un]idle signals and update from there
872 if (ops != NULL && ops->update != NULL)
873 ops->update(purple_blist_get_buddy_list(), (PurpleBlistNode *)buddy);
875 g_date_time_unref(current_time);
878 PurpleBuddy *
879 purple_buddy_presence_get_buddy(const PurpleBuddyPresence *presence)
881 PurpleBuddyPresencePrivate *priv = PURPLE_BUDDY_PRESENCE_GET_PRIVATE(presence);
883 g_return_val_if_fail(priv != NULL, NULL);
885 return priv->buddy;
888 /**************************************************************************
889 * GObject code for PurpleBuddyPresence
890 **************************************************************************/
892 /* Set method for GObject properties */
893 static void
894 purple_buddy_presence_set_property(GObject *obj, guint param_id, const GValue *value,
895 GParamSpec *pspec)
897 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
898 PurpleBuddyPresencePrivate *priv =
899 PURPLE_BUDDY_PRESENCE_GET_PRIVATE(buddy_presence);
901 switch (param_id) {
902 case BUDPRES_PROP_BUDDY:
903 priv->buddy = g_value_get_object(value);
904 break;
905 default:
906 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
907 break;
911 /* Get method for GObject properties */
912 static void
913 purple_buddy_presence_get_property(GObject *obj, guint param_id, GValue *value,
914 GParamSpec *pspec)
916 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
918 switch (param_id) {
919 case BUDPRES_PROP_BUDDY:
920 g_value_set_object(value,
921 purple_buddy_presence_get_buddy(buddy_presence));
922 break;
923 default:
924 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
925 break;
929 /* Called when done constructing */
930 static void
931 purple_buddy_presence_constructed(GObject *object)
933 PurplePresence *presence = PURPLE_PRESENCE(object);
934 PurpleBuddyPresencePrivate *priv = PURPLE_BUDDY_PRESENCE_GET_PRIVATE(presence);
935 PurpleAccount *account;
937 G_OBJECT_CLASS(presence_class)->constructed(object);
939 account = purple_buddy_get_account(priv->buddy);
940 PURPLE_PRESENCE_GET_PRIVATE(presence)->statuses =
941 purple_protocol_get_statuses(account, presence);
944 /* Class initializer function */
945 static void purple_buddy_presence_class_init(PurpleBuddyPresenceClass *klass)
947 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
949 PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_buddy_presence_update_idle;
951 presence_class = g_type_class_peek_parent(klass);
953 obj_class->constructed = purple_buddy_presence_constructed;
955 /* Setup properties */
956 obj_class->get_property = purple_buddy_presence_get_property;
957 obj_class->set_property = purple_buddy_presence_set_property;
959 g_type_class_add_private(klass, sizeof(PurpleBuddyPresencePrivate));
961 bp_properties[BUDPRES_PROP_BUDDY] = g_param_spec_object("buddy", "Buddy",
962 "The buddy that this presence is of.", PURPLE_TYPE_BUDDY,
963 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
964 G_PARAM_STATIC_STRINGS);
966 g_object_class_install_properties(obj_class, BUDPRES_PROP_LAST,
967 bp_properties);
970 GType
971 purple_buddy_presence_get_type(void)
973 static GType type = 0;
975 if(type == 0) {
976 static const GTypeInfo info = {
977 sizeof(PurpleBuddyPresenceClass),
978 NULL,
979 NULL,
980 (GClassInitFunc)purple_buddy_presence_class_init,
981 NULL,
982 NULL,
983 sizeof(PurpleBuddyPresence),
985 NULL,
986 NULL,
989 type = g_type_register_static(PURPLE_TYPE_PRESENCE,
990 "PurpleBuddyPresence",
991 &info, 0);
994 return type;
997 PurpleBuddyPresence *
998 purple_buddy_presence_new(PurpleBuddy *buddy)
1000 g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
1002 return g_object_new(PURPLE_TYPE_BUDDY_PRESENCE,
1003 "buddy", buddy,
1004 NULL);