Merge heads.
[pidgin-git.git] / libpurple / presence.c
blob215f1c34593a87c07dfe59aeba9963a115f7ccc8
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 "presence.h"
26 /**************************************************************************
27 * PurplePresence
28 **************************************************************************/
30 /** Private data for a presence */
31 typedef struct
33 gboolean idle;
34 time_t idle_time;
35 time_t login_time;
37 GList *statuses;
38 GHashTable *status_table;
40 PurpleStatus *active_status;
41 } PurplePresencePrivate;
43 /* Presence property enums */
44 enum
46 PRES_PROP_0,
47 PRES_PROP_IDLE,
48 PRES_PROP_IDLE_TIME,
49 PRES_PROP_LOGIN_TIME,
50 PRES_PROP_STATUSES,
51 PRES_PROP_ACTIVE_STATUS,
52 PRES_PROP_LAST
55 static GParamSpec *properties[PRES_PROP_LAST];
57 G_DEFINE_TYPE_WITH_PRIVATE(PurplePresence, purple_presence, G_TYPE_OBJECT)
59 /**************************************************************************
60 * PurpleAccountPresence
61 **************************************************************************/
63 /**
64 * PurpleAccountPresence:
66 * A presence for an account
68 struct _PurpleAccountPresence
70 PurplePresence parent;
73 /** Private data for an account presence */
74 typedef struct
76 PurpleAccount *account;
77 } PurpleAccountPresencePrivate;
79 /* Account presence property enums */
80 enum
82 ACPRES_PROP_0,
83 ACPRES_PROP_ACCOUNT,
84 ACPRES_PROP_LAST
87 static GParamSpec *ap_properties[ACPRES_PROP_LAST];
89 G_DEFINE_TYPE_WITH_PRIVATE(PurpleAccountPresence, purple_account_presence,
90 PURPLE_TYPE_PRESENCE)
92 /**************************************************************************
93 * PurpleBuddyPresence
94 **************************************************************************/
96 /**
97 * PurpleBuddyPresence:
99 * A presence for a buddy
101 struct _PurpleBuddyPresence
103 PurplePresence parent;
106 /** Private data for a buddy presence */
107 typedef struct
109 PurpleBuddy *buddy;
110 } PurpleBuddyPresencePrivate;
112 /* Buddy presence property enums */
113 enum
115 BUDPRES_PROP_0,
116 BUDPRES_PROP_BUDDY,
117 BUDPRES_PROP_LAST
120 static GParamSpec *bp_properties[BUDPRES_PROP_LAST];
122 G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddyPresence, purple_buddy_presence,
123 PURPLE_TYPE_PRESENCE)
125 /**************************************************************************
126 * PurplePresence API
127 **************************************************************************/
129 void
130 purple_presence_set_status_active(PurplePresence *presence, const char *status_id,
131 gboolean active)
133 PurpleStatus *status;
135 g_return_if_fail(PURPLE_IS_PRESENCE(presence));
136 g_return_if_fail(status_id != NULL);
138 status = purple_presence_get_status(presence, status_id);
140 g_return_if_fail(PURPLE_IS_STATUS(status));
141 /* TODO: Should we do the following? */
142 /* g_return_if_fail(active == status->active); */
144 if (purple_status_is_exclusive(status))
146 if (!active)
148 purple_debug_warning("presence",
149 "Attempted to set a non-independent status "
150 "(%s) inactive. Only independent statuses "
151 "can be specifically marked inactive.",
152 status_id);
153 return;
157 purple_status_set_active(status, active);
160 void
161 purple_presence_switch_status(PurplePresence *presence, const char *status_id)
163 purple_presence_set_status_active(presence, status_id, TRUE);
166 void
167 purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time)
169 PurplePresencePrivate *priv = NULL;
170 PurplePresenceClass *klass = NULL;
171 gboolean old_idle;
172 GObject *obj;
174 g_return_if_fail(PURPLE_IS_PRESENCE(presence));
176 priv = purple_presence_get_instance_private(presence);
177 klass = PURPLE_PRESENCE_GET_CLASS(presence);
179 if (priv->idle == idle && priv->idle_time == idle_time)
180 return;
182 old_idle = priv->idle;
183 priv->idle = idle;
184 priv->idle_time = (idle ? idle_time : 0);
186 obj = G_OBJECT(presence);
187 g_object_freeze_notify(obj);
188 g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE]);
189 g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE_TIME]);
190 g_object_thaw_notify(obj);
192 if (klass->update_idle)
193 klass->update_idle(presence, old_idle);
196 void
197 purple_presence_set_login_time(PurplePresence *presence, time_t login_time)
199 PurplePresencePrivate *priv = NULL;
201 g_return_if_fail(PURPLE_IS_PRESENCE(presence));
203 priv = purple_presence_get_instance_private(presence);
205 if (priv->login_time == login_time)
206 return;
208 priv->login_time = login_time;
210 g_object_notify_by_pspec(G_OBJECT(presence),
211 properties[PRES_PROP_LOGIN_TIME]);
214 GList *
215 purple_presence_get_statuses(PurplePresence *presence)
217 PurplePresencePrivate *priv = NULL;
219 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL);
221 priv = purple_presence_get_instance_private(presence);
222 return priv->statuses;
225 PurpleStatus *
226 purple_presence_get_status(PurplePresence *presence, const char *status_id)
228 PurplePresencePrivate *priv = NULL;
229 PurpleStatus *status;
230 GList *l = NULL;
232 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL);
233 g_return_val_if_fail(status_id != NULL, NULL);
235 priv = purple_presence_get_instance_private(presence);
237 /* What's the purpose of this hash table? */
238 status = (PurpleStatus *)g_hash_table_lookup(priv->status_table,
239 status_id);
241 if (status == NULL) {
242 for (l = purple_presence_get_statuses(presence);
243 l != NULL && status == NULL; l = l->next)
245 PurpleStatus *temp_status = l->data;
247 if (purple_strequal(status_id, purple_status_get_id(temp_status)))
248 status = temp_status;
251 if (status != NULL)
252 g_hash_table_insert(priv->status_table,
253 g_strdup(purple_status_get_id(status)), status);
256 return status;
259 PurpleStatus *
260 purple_presence_get_active_status(PurplePresence *presence)
262 PurplePresencePrivate *priv = NULL;
264 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), NULL);
266 priv = purple_presence_get_instance_private(presence);
267 return priv->active_status;
270 gboolean
271 purple_presence_is_available(PurplePresence *presence)
273 PurpleStatus *status;
275 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
277 status = purple_presence_get_active_status(presence);
279 return ((status != NULL && purple_status_is_available(status)) &&
280 !purple_presence_is_idle(presence));
283 gboolean
284 purple_presence_is_online(PurplePresence *presence)
286 PurpleStatus *status;
288 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
290 if ((status = purple_presence_get_active_status(presence)) == NULL)
291 return FALSE;
293 return purple_status_is_online(status);
296 gboolean
297 purple_presence_is_status_active(PurplePresence *presence,
298 const char *status_id)
300 PurpleStatus *status;
302 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
303 g_return_val_if_fail(status_id != NULL, FALSE);
305 status = purple_presence_get_status(presence, status_id);
307 return (status != NULL && purple_status_is_active(status));
310 gboolean
311 purple_presence_is_status_primitive_active(PurplePresence *presence,
312 PurpleStatusPrimitive primitive)
314 GList *l;
316 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
317 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, FALSE);
319 for (l = purple_presence_get_statuses(presence);
320 l != NULL; l = l->next)
322 PurpleStatus *temp_status = l->data;
323 PurpleStatusType *type = purple_status_get_status_type(temp_status);
325 if (purple_status_type_get_primitive(type) == primitive &&
326 purple_status_is_active(temp_status))
327 return TRUE;
329 return FALSE;
332 gboolean
333 purple_presence_is_idle(PurplePresence *presence)
335 PurplePresencePrivate *priv = NULL;
337 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
339 priv = purple_presence_get_instance_private(presence);
340 return purple_presence_is_online(presence) && priv->idle;
343 time_t
344 purple_presence_get_idle_time(PurplePresence *presence)
346 PurplePresencePrivate *priv = NULL;
348 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), 0);
350 priv = purple_presence_get_instance_private(presence);
351 return priv->idle_time;
354 time_t
355 purple_presence_get_login_time(PurplePresence *presence)
357 PurplePresencePrivate *priv = NULL;
359 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), 0);
361 priv = purple_presence_get_instance_private(presence);
362 return purple_presence_is_online(presence) ? priv->login_time : 0;
365 /**************************************************************************
366 * GObject code for PurplePresence
367 **************************************************************************/
369 /* Set method for GObject properties */
370 static void
371 purple_presence_set_property(GObject *obj, guint param_id, const GValue *value,
372 GParamSpec *pspec)
374 PurplePresence *presence = PURPLE_PRESENCE(obj);
375 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
377 switch (param_id) {
378 case PRES_PROP_IDLE:
379 purple_presence_set_idle(presence, g_value_get_boolean(value), 0);
380 break;
381 case PRES_PROP_IDLE_TIME:
382 #if SIZEOF_TIME_T == 4
383 purple_presence_set_idle(presence, TRUE, g_value_get_int(value));
384 #elif SIZEOF_TIME_T == 8
385 purple_presence_set_idle(presence, TRUE, g_value_get_int64(value));
386 #else
387 #error Unknown size of time_t
388 #endif
389 break;
390 case PRES_PROP_LOGIN_TIME:
391 #if SIZEOF_TIME_T == 4
392 purple_presence_set_login_time(presence, g_value_get_int(value));
393 #elif SIZEOF_TIME_T == 8
394 purple_presence_set_login_time(presence, g_value_get_int64(value));
395 #else
396 #error Unknown size of time_t
397 #endif
398 break;
399 case PRES_PROP_ACTIVE_STATUS:
400 priv->active_status = g_value_get_object(value);
401 break;
402 default:
403 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
404 break;
408 /* Get method for GObject properties */
409 static void
410 purple_presence_get_property(GObject *obj, guint param_id, GValue *value,
411 GParamSpec *pspec)
413 PurplePresence *presence = PURPLE_PRESENCE(obj);
415 switch (param_id) {
416 case PRES_PROP_IDLE:
417 g_value_set_boolean(value, purple_presence_is_idle(presence));
418 break;
419 case PRES_PROP_IDLE_TIME:
420 #if SIZEOF_TIME_T == 4
421 g_value_set_int(value, purple_presence_get_idle_time(presence));
422 #elif SIZEOF_TIME_T == 8
423 g_value_set_int64(value, purple_presence_get_idle_time(presence));
424 #else
425 #error Unknown size of time_t
426 #endif
427 break;
428 case PRES_PROP_LOGIN_TIME:
429 #if SIZEOF_TIME_T == 4
430 g_value_set_int(value, purple_presence_get_login_time(presence));
431 #elif SIZEOF_TIME_T == 8
432 g_value_set_int64(value, purple_presence_get_login_time(presence));
433 #else
434 #error Unknown size of time_t
435 #endif
436 break;
437 case PRES_PROP_STATUSES:
438 g_value_set_pointer(value, purple_presence_get_statuses(presence));
439 break;
440 case PRES_PROP_ACTIVE_STATUS:
441 g_value_set_object(value, purple_presence_get_active_status(presence));
442 break;
443 default:
444 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
445 break;
449 /* GObject initialization function */
450 static void
451 purple_presence_init(PurplePresence *presence)
453 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
454 priv->status_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
457 /* GObject dispose function */
458 static void
459 purple_presence_dispose(GObject *object)
461 PurplePresencePrivate *priv =
462 purple_presence_get_instance_private(PURPLE_PRESENCE(object));
464 if (priv->statuses) {
465 g_list_free_full(priv->statuses, (GDestroyNotify)g_object_unref);
466 priv->statuses = NULL;
469 G_OBJECT_CLASS(purple_presence_parent_class)->dispose(object);
472 /* GObject finalize function */
473 static void
474 purple_presence_finalize(GObject *object)
476 PurplePresencePrivate *priv =
477 purple_presence_get_instance_private(PURPLE_PRESENCE(object));
479 g_hash_table_destroy(priv->status_table);
481 G_OBJECT_CLASS(purple_presence_parent_class)->finalize(object);
484 /* Class initializer function */
485 static void purple_presence_class_init(PurplePresenceClass *klass)
487 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
489 obj_class->dispose = purple_presence_dispose;
490 obj_class->finalize = purple_presence_finalize;
492 /* Setup properties */
493 obj_class->get_property = purple_presence_get_property;
494 obj_class->set_property = purple_presence_set_property;
496 properties[PRES_PROP_IDLE] = g_param_spec_boolean("idle", "Idle",
497 "Whether the presence is in idle state.", FALSE,
498 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
500 properties[PRES_PROP_IDLE_TIME] =
501 #if SIZEOF_TIME_T == 4
502 g_param_spec_int
503 #elif SIZEOF_TIME_T == 8
504 g_param_spec_int64
505 #else
506 #error Unknown size of time_t
507 #endif
508 ("idle-time", "Idle time",
509 "The idle time of the presence",
510 #if SIZEOF_TIME_T == 4
511 G_MININT, G_MAXINT, 0,
512 #elif SIZEOF_TIME_T == 8
513 G_MININT64, G_MAXINT64, 0,
514 #else
515 #error Unknown size of time_t
516 #endif
517 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
519 properties[PRES_PROP_LOGIN_TIME] =
520 #if SIZEOF_TIME_T == 4
521 g_param_spec_int
522 #elif SIZEOF_TIME_T == 8
523 g_param_spec_int64
524 #else
525 #error Unknown size of time_t
526 #endif
527 ("login-time", "Login time",
528 "The login time of the presence.",
529 #if SIZEOF_TIME_T == 4
530 G_MININT, G_MAXINT, 0,
531 #elif SIZEOF_TIME_T == 8
532 G_MININT64, G_MAXINT64, 0,
533 #else
534 #error Unknown size of time_t
535 #endif
536 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
538 properties[PRES_PROP_STATUSES] = g_param_spec_pointer("statuses",
539 "Statuses",
540 "The list of statuses in the presence.",
541 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
543 properties[PRES_PROP_ACTIVE_STATUS] = g_param_spec_object("active-status",
544 "Active status",
545 "The active status for the presence.", PURPLE_TYPE_STATUS,
546 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
548 g_object_class_install_properties(obj_class, PRES_PROP_LAST, properties);
551 /**************************************************************************
552 * PurpleAccountPresence API
553 **************************************************************************/
554 static void
555 purple_account_presence_update_idle(PurplePresence *presence, gboolean old_idle)
557 PurpleAccount *account;
558 PurpleConnection *gc = NULL;
559 PurpleProtocol *protocol = NULL;
560 gboolean idle = purple_presence_is_idle(presence);
561 time_t idle_time = purple_presence_get_idle_time(presence);
562 time_t current_time = time(NULL);
564 account = purple_account_presence_get_account(PURPLE_ACCOUNT_PRESENCE(presence));
566 if (purple_prefs_get_bool("/purple/logging/log_system"))
568 PurpleLog *log = purple_account_get_log(account, FALSE);
570 if (log != NULL)
572 char *msg, *tmp;
573 GDateTime *dt;
575 if (idle) {
576 tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
577 dt = g_date_time_new_from_unix_local(idle_time);
578 } else {
579 tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
580 dt = g_date_time_new_now_utc();
583 msg = g_markup_escape_text(tmp, -1);
584 g_free(tmp);
585 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
586 purple_account_get_username(account),
587 dt, msg);
588 g_date_time_unref(dt);
589 g_free(msg);
593 gc = purple_account_get_connection(account);
595 if(PURPLE_CONNECTION_IS_CONNECTED(gc))
596 protocol = purple_connection_get_protocol(gc);
598 if (protocol)
599 purple_protocol_server_iface_set_idle(protocol, gc, (idle ? (current_time - idle_time) : 0));
602 PurpleAccount *
603 purple_account_presence_get_account(PurpleAccountPresence *presence)
605 PurpleAccountPresencePrivate *priv = NULL;
607 g_return_val_if_fail(PURPLE_IS_ACCOUNT_PRESENCE(presence), NULL);
609 priv = purple_account_presence_get_instance_private(presence);
610 return priv->account;
613 static int
614 purple_buddy_presence_compute_score(PurpleBuddyPresence *buddy_presence)
616 GList *l;
617 int score = 0;
618 PurplePresence *presence = PURPLE_PRESENCE(buddy_presence);
619 PurpleBuddy *b = purple_buddy_presence_get_buddy(buddy_presence);
620 int *primitive_scores = _purple_statuses_get_primitive_scores();
621 int offline_score = purple_prefs_get_int("/purple/status/scores/offline_msg");
622 int idle_score = purple_prefs_get_int("/purple/status/scores/idle");
624 for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) {
625 PurpleStatus *status = (PurpleStatus *)l->data;
626 PurpleStatusType *type = purple_status_get_status_type(status);
628 if (purple_status_is_active(status)) {
629 score += primitive_scores[purple_status_type_get_primitive(type)];
630 if (!purple_status_is_online(status)) {
631 if (b && purple_account_supports_offline_message(purple_buddy_get_account(b), b))
632 score += offline_score;
636 score += purple_account_get_int(purple_buddy_get_account(b), "score", 0);
637 if (purple_presence_is_idle(presence))
638 score += idle_score;
639 return score;
642 gint
643 purple_buddy_presence_compare(PurpleBuddyPresence *buddy_presence1,
644 PurpleBuddyPresence *buddy_presence2)
646 PurplePresence *presence1 = PURPLE_PRESENCE(buddy_presence1);
647 PurplePresence *presence2 = PURPLE_PRESENCE(buddy_presence2);
648 time_t idle_time_1, idle_time_2;
649 int score1 = 0, score2 = 0;
650 int idle_time_score = purple_prefs_get_int("/purple/status/scores/idle_time");
652 if (presence1 == presence2)
653 return 0;
654 else if (presence1 == NULL)
655 return 1;
656 else if (presence2 == NULL)
657 return -1;
659 if (purple_presence_is_online(presence1) &&
660 !purple_presence_is_online(presence2))
661 return -1;
662 else if (purple_presence_is_online(presence2) &&
663 !purple_presence_is_online(presence1))
664 return 1;
666 /* Compute the score of the first set of statuses. */
667 score1 = purple_buddy_presence_compute_score(buddy_presence1);
669 /* Compute the score of the second set of statuses. */
670 score2 = purple_buddy_presence_compute_score(buddy_presence2);
672 idle_time_1 = time(NULL) - purple_presence_get_idle_time(presence1);
673 idle_time_2 = time(NULL) - purple_presence_get_idle_time(presence2);
675 if (idle_time_1 > idle_time_2)
676 score1 += idle_time_score;
677 else if (idle_time_1 < idle_time_2)
678 score2 += idle_time_score;
680 if (score1 < score2)
681 return 1;
682 else if (score1 > score2)
683 return -1;
685 return 0;
688 /**************************************************************************
689 * GObject code for PurpleAccountPresence
690 **************************************************************************/
692 /* Set method for GObject properties */
693 static void
694 purple_account_presence_set_property(GObject *obj, guint param_id, const GValue *value,
695 GParamSpec *pspec)
697 PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj);
698 PurpleAccountPresencePrivate *priv =
699 purple_account_presence_get_instance_private(account_presence);
701 switch (param_id) {
702 case ACPRES_PROP_ACCOUNT:
703 priv->account = g_value_get_object(value);
704 break;
705 default:
706 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
707 break;
711 /* Get method for GObject properties */
712 static void
713 purple_account_presence_get_property(GObject *obj, guint param_id, GValue *value,
714 GParamSpec *pspec)
716 PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj);
718 switch (param_id) {
719 case ACPRES_PROP_ACCOUNT:
720 g_value_set_object(value,
721 purple_account_presence_get_account(account_presence));
722 break;
723 default:
724 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
725 break;
729 /* Called when done constructing */
730 static void
731 purple_account_presence_constructed(GObject *object)
733 PurplePresence *presence = PURPLE_PRESENCE(object);
734 PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence);
735 PurpleAccountPresencePrivate *account_priv =
736 purple_account_presence_get_instance_private(PURPLE_ACCOUNT_PRESENCE(presence));
738 G_OBJECT_CLASS(purple_account_presence_parent_class)->constructed(object);
740 parent_priv->statuses = purple_protocol_get_statuses(account_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 obj_class->constructed = purple_account_presence_constructed;
752 /* Setup properties */
753 obj_class->get_property = purple_account_presence_get_property;
754 obj_class->set_property = purple_account_presence_set_property;
756 ap_properties[ACPRES_PROP_ACCOUNT] = g_param_spec_object("account",
757 "Account",
758 "The account that this presence is of.", PURPLE_TYPE_ACCOUNT,
759 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
760 G_PARAM_STATIC_STRINGS);
762 g_object_class_install_properties(obj_class, ACPRES_PROP_LAST,
763 ap_properties);
766 static void
767 purple_account_presence_init(PurpleAccountPresence *presence)
771 PurpleAccountPresence *
772 purple_account_presence_new(PurpleAccount *account)
774 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
776 return g_object_new(PURPLE_TYPE_ACCOUNT_PRESENCE,
777 "account", account,
778 NULL);
781 /**************************************************************************
782 * PurpleBuddyPresence API
783 **************************************************************************/
784 static void
785 purple_buddy_presence_update_idle(PurplePresence *presence, gboolean old_idle)
787 PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(presence));
788 GDateTime *current_time = g_date_time_new_now_utc();
789 PurpleAccount *account = purple_buddy_get_account(buddy);
790 gboolean idle = purple_presence_is_idle(presence);
792 if (!old_idle && idle)
794 if (purple_prefs_get_bool("/purple/logging/log_system"))
796 PurpleLog *log = purple_account_get_log(account, FALSE);
798 if (log != NULL)
800 char *tmp, *tmp2;
801 tmp = g_strdup_printf(_("%s became idle"),
802 purple_buddy_get_alias(buddy));
803 tmp2 = g_markup_escape_text(tmp, -1);
804 g_free(tmp);
806 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
807 purple_buddy_get_alias(buddy),
808 current_time, tmp2);
809 g_free(tmp2);
813 else if (old_idle && !idle)
815 if (purple_prefs_get_bool("/purple/logging/log_system"))
817 PurpleLog *log = purple_account_get_log(account, FALSE);
819 if (log != NULL)
821 char *tmp, *tmp2;
822 tmp = g_strdup_printf(_("%s became unidle"),
823 purple_buddy_get_alias(buddy));
824 tmp2 = g_markup_escape_text(tmp, -1);
825 g_free(tmp);
827 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
828 purple_buddy_get_alias(buddy),
829 current_time, tmp2);
830 g_free(tmp2);
835 if (old_idle != idle)
836 purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
837 old_idle, idle);
839 purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
841 /* Should this be done here? It'd perhaps make more sense to
842 * connect to buddy-[un]idle signals and update from there
845 purple_blist_update_node(purple_blist_get_default(),
846 PURPLE_BLIST_NODE(buddy));
848 g_date_time_unref(current_time);
851 PurpleBuddy *
852 purple_buddy_presence_get_buddy(PurpleBuddyPresence *presence)
854 PurpleBuddyPresencePrivate *priv = NULL;
856 g_return_val_if_fail(PURPLE_IS_BUDDY_PRESENCE(presence), NULL);
858 priv = purple_buddy_presence_get_instance_private(presence);
859 return priv->buddy;
862 /**************************************************************************
863 * GObject code for PurpleBuddyPresence
864 **************************************************************************/
866 /* Set method for GObject properties */
867 static void
868 purple_buddy_presence_set_property(GObject *obj, guint param_id, const GValue *value,
869 GParamSpec *pspec)
871 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
872 PurpleBuddyPresencePrivate *priv =
873 purple_buddy_presence_get_instance_private(buddy_presence);
875 switch (param_id) {
876 case BUDPRES_PROP_BUDDY:
877 priv->buddy = g_value_get_object(value);
878 break;
879 default:
880 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
881 break;
885 /* Get method for GObject properties */
886 static void
887 purple_buddy_presence_get_property(GObject *obj, guint param_id, GValue *value,
888 GParamSpec *pspec)
890 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
892 switch (param_id) {
893 case BUDPRES_PROP_BUDDY:
894 g_value_set_object(value,
895 purple_buddy_presence_get_buddy(buddy_presence));
896 break;
897 default:
898 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
899 break;
903 /* Called when done constructing */
904 static void
905 purple_buddy_presence_constructed(GObject *object)
907 PurplePresence *presence = PURPLE_PRESENCE(object);
908 PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence);
909 PurpleBuddyPresencePrivate *buddy_priv =
910 purple_buddy_presence_get_instance_private(PURPLE_BUDDY_PRESENCE(presence));
911 PurpleAccount *account;
913 G_OBJECT_CLASS(purple_buddy_presence_parent_class)->constructed(object);
915 account = purple_buddy_get_account(buddy_priv->buddy);
916 parent_priv->statuses = purple_protocol_get_statuses(account, presence);
919 /* Class initializer function */
920 static void purple_buddy_presence_class_init(PurpleBuddyPresenceClass *klass)
922 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
924 PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_buddy_presence_update_idle;
926 obj_class->constructed = purple_buddy_presence_constructed;
928 /* Setup properties */
929 obj_class->get_property = purple_buddy_presence_get_property;
930 obj_class->set_property = purple_buddy_presence_set_property;
932 bp_properties[BUDPRES_PROP_BUDDY] = g_param_spec_object("buddy", "Buddy",
933 "The buddy that this presence is of.", PURPLE_TYPE_BUDDY,
934 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
935 G_PARAM_STATIC_STRINGS);
937 g_object_class_install_properties(obj_class, BUDPRES_PROP_LAST,
938 bp_properties);
941 static void
942 purple_buddy_presence_init(PurpleBuddyPresence *presence)
946 PurpleBuddyPresence *
947 purple_buddy_presence_new(PurpleBuddy *buddy)
949 g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
951 return g_object_new(PURPLE_TYPE_BUDDY_PRESENCE,
952 "buddy", buddy,
953 NULL);