Use G_DEFINE_TYPE_WITH_PRIVATE for Purple*Presence.
[pidgin-git.git] / libpurple / presence.c
blobcedbb810e9a78d95f885507a2dda4a83b348228b
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 /** @copydoc _PurplePresencePrivate */
27 typedef struct _PurplePresencePrivate PurplePresencePrivate;
29 /** @copydoc _PurpleAccountPresencePrivate */
30 typedef struct _PurpleAccountPresencePrivate PurpleAccountPresencePrivate;
32 /** @copydoc _PurpleBuddyPresencePrivate */
33 typedef struct _PurpleBuddyPresencePrivate PurpleBuddyPresencePrivate;
35 /** Private data for a presence */
36 struct _PurplePresencePrivate
38 gboolean idle;
39 time_t idle_time;
40 time_t login_time;
42 GList *statuses;
43 GHashTable *status_table;
45 PurpleStatus *active_status;
48 /* Presence property enums */
49 enum
51 PRES_PROP_0,
52 PRES_PROP_IDLE,
53 PRES_PROP_IDLE_TIME,
54 PRES_PROP_LOGIN_TIME,
55 PRES_PROP_STATUSES,
56 PRES_PROP_ACTIVE_STATUS,
57 PRES_PROP_LAST
60 /** Private data for an account presence */
61 struct _PurpleAccountPresencePrivate
63 PurpleAccount *account;
66 /* Account presence property enums */
67 enum
69 ACPRES_PROP_0,
70 ACPRES_PROP_ACCOUNT,
71 ACPRES_PROP_LAST
74 /** Private data for a buddy presence */
75 struct _PurpleBuddyPresencePrivate
77 PurpleBuddy *buddy;
80 /* Buddy presence property enums */
81 enum
83 BUDPRES_PROP_0,
84 BUDPRES_PROP_BUDDY,
85 BUDPRES_PROP_LAST
88 static GParamSpec *properties[PRES_PROP_LAST];
89 static GParamSpec *ap_properties[ACPRES_PROP_LAST];
90 static GParamSpec *bp_properties[BUDPRES_PROP_LAST];
92 G_DEFINE_TYPE_WITH_PRIVATE(PurplePresence, purple_presence, G_TYPE_OBJECT)
93 G_DEFINE_TYPE_WITH_PRIVATE(PurpleAccountPresence, purple_account_presence,
94 PURPLE_TYPE_PRESENCE)
95 G_DEFINE_TYPE_WITH_PRIVATE(PurpleBuddyPresence, purple_buddy_presence,
96 PURPLE_TYPE_PRESENCE)
98 /**************************************************************************
99 * PurplePresence API
100 **************************************************************************/
102 void
103 purple_presence_set_status_active(PurplePresence *presence, const char *status_id,
104 gboolean active)
106 PurpleStatus *status;
108 g_return_if_fail(PURPLE_IS_PRESENCE(presence));
109 g_return_if_fail(status_id != NULL);
111 status = purple_presence_get_status(presence, status_id);
113 g_return_if_fail(PURPLE_IS_STATUS(status));
114 /* TODO: Should we do the following? */
115 /* g_return_if_fail(active == status->active); */
117 if (purple_status_is_exclusive(status))
119 if (!active)
121 purple_debug_warning("presence",
122 "Attempted to set a non-independent status "
123 "(%s) inactive. Only independent statuses "
124 "can be specifically marked inactive.",
125 status_id);
126 return;
130 purple_status_set_active(status, active);
133 void
134 purple_presence_switch_status(PurplePresence *presence, const char *status_id)
136 purple_presence_set_status_active(presence, status_id, TRUE);
139 void
140 purple_presence_set_idle(PurplePresence *presence, gboolean idle, time_t idle_time)
142 gboolean old_idle;
143 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
144 PurplePresenceClass *klass = PURPLE_PRESENCE_GET_CLASS(presence);
145 GObject *obj;
147 g_return_if_fail(priv != NULL);
149 if (priv->idle == idle && priv->idle_time == idle_time)
150 return;
152 old_idle = priv->idle;
153 priv->idle = idle;
154 priv->idle_time = (idle ? idle_time : 0);
156 obj = G_OBJECT(presence);
157 g_object_freeze_notify(obj);
158 g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE]);
159 g_object_notify_by_pspec(obj, properties[PRES_PROP_IDLE_TIME]);
160 g_object_thaw_notify(obj);
162 if (klass->update_idle)
163 klass->update_idle(presence, old_idle);
166 void
167 purple_presence_set_login_time(PurplePresence *presence, time_t login_time)
169 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
171 g_return_if_fail(priv != NULL);
173 if (priv->login_time == login_time)
174 return;
176 priv->login_time = login_time;
178 g_object_notify_by_pspec(G_OBJECT(presence),
179 properties[PRES_PROP_LOGIN_TIME]);
182 GList *
183 purple_presence_get_statuses(PurplePresence *presence)
185 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
187 g_return_val_if_fail(priv != NULL, NULL);
189 return priv->statuses;
192 PurpleStatus *
193 purple_presence_get_status(PurplePresence *presence, const char *status_id)
195 PurpleStatus *status;
196 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
197 GList *l = NULL;
199 g_return_val_if_fail(priv != NULL, NULL);
200 g_return_val_if_fail(status_id != NULL, NULL);
202 /* What's the purpose of this hash table? */
203 status = (PurpleStatus *)g_hash_table_lookup(priv->status_table,
204 status_id);
206 if (status == NULL) {
207 for (l = purple_presence_get_statuses(presence);
208 l != NULL && status == NULL; l = l->next)
210 PurpleStatus *temp_status = l->data;
212 if (purple_strequal(status_id, purple_status_get_id(temp_status)))
213 status = temp_status;
216 if (status != NULL)
217 g_hash_table_insert(priv->status_table,
218 g_strdup(purple_status_get_id(status)), status);
221 return status;
224 PurpleStatus *
225 purple_presence_get_active_status(PurplePresence *presence)
227 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
229 g_return_val_if_fail(priv != NULL, NULL);
231 return priv->active_status;
234 gboolean
235 purple_presence_is_available(PurplePresence *presence)
237 PurpleStatus *status;
239 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
241 status = purple_presence_get_active_status(presence);
243 return ((status != NULL && purple_status_is_available(status)) &&
244 !purple_presence_is_idle(presence));
247 gboolean
248 purple_presence_is_online(PurplePresence *presence)
250 PurpleStatus *status;
252 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
254 if ((status = purple_presence_get_active_status(presence)) == NULL)
255 return FALSE;
257 return purple_status_is_online(status);
260 gboolean
261 purple_presence_is_status_active(PurplePresence *presence,
262 const char *status_id)
264 PurpleStatus *status;
266 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
267 g_return_val_if_fail(status_id != NULL, FALSE);
269 status = purple_presence_get_status(presence, status_id);
271 return (status != NULL && purple_status_is_active(status));
274 gboolean
275 purple_presence_is_status_primitive_active(PurplePresence *presence,
276 PurpleStatusPrimitive primitive)
278 GList *l;
280 g_return_val_if_fail(PURPLE_IS_PRESENCE(presence), FALSE);
281 g_return_val_if_fail(primitive != PURPLE_STATUS_UNSET, FALSE);
283 for (l = purple_presence_get_statuses(presence);
284 l != NULL; l = l->next)
286 PurpleStatus *temp_status = l->data;
287 PurpleStatusType *type = purple_status_get_status_type(temp_status);
289 if (purple_status_type_get_primitive(type) == primitive &&
290 purple_status_is_active(temp_status))
291 return TRUE;
293 return FALSE;
296 gboolean
297 purple_presence_is_idle(PurplePresence *presence)
299 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
301 g_return_val_if_fail(priv != NULL, FALSE);
303 return purple_presence_is_online(presence) && priv->idle;
306 time_t
307 purple_presence_get_idle_time(PurplePresence *presence)
309 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
311 g_return_val_if_fail(priv != NULL, 0);
313 return priv->idle_time;
316 time_t
317 purple_presence_get_login_time(PurplePresence *presence)
319 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
321 g_return_val_if_fail(priv != NULL, 0);
323 return purple_presence_is_online(presence) ? priv->login_time : 0;
326 /**************************************************************************
327 * GObject code for PurplePresence
328 **************************************************************************/
330 /* Set method for GObject properties */
331 static void
332 purple_presence_set_property(GObject *obj, guint param_id, const GValue *value,
333 GParamSpec *pspec)
335 PurplePresence *presence = PURPLE_PRESENCE(obj);
336 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
338 switch (param_id) {
339 case PRES_PROP_IDLE:
340 purple_presence_set_idle(presence, g_value_get_boolean(value), 0);
341 break;
342 case PRES_PROP_IDLE_TIME:
343 #if SIZEOF_TIME_T == 4
344 purple_presence_set_idle(presence, TRUE, g_value_get_int(value));
345 #elif SIZEOF_TIME_T == 8
346 purple_presence_set_idle(presence, TRUE, g_value_get_int64(value));
347 #else
348 #error Unknown size of time_t
349 #endif
350 break;
351 case PRES_PROP_LOGIN_TIME:
352 #if SIZEOF_TIME_T == 4
353 purple_presence_set_login_time(presence, g_value_get_int(value));
354 #elif SIZEOF_TIME_T == 8
355 purple_presence_set_login_time(presence, g_value_get_int64(value));
356 #else
357 #error Unknown size of time_t
358 #endif
359 break;
360 case PRES_PROP_ACTIVE_STATUS:
361 priv->active_status = g_value_get_object(value);
362 break;
363 default:
364 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
365 break;
369 /* Get method for GObject properties */
370 static void
371 purple_presence_get_property(GObject *obj, guint param_id, GValue *value,
372 GParamSpec *pspec)
374 PurplePresence *presence = PURPLE_PRESENCE(obj);
376 switch (param_id) {
377 case PRES_PROP_IDLE:
378 g_value_set_boolean(value, purple_presence_is_idle(presence));
379 break;
380 case PRES_PROP_IDLE_TIME:
381 #if SIZEOF_TIME_T == 4
382 g_value_set_int(value, purple_presence_get_idle_time(presence));
383 #elif SIZEOF_TIME_T == 8
384 g_value_set_int64(value, purple_presence_get_idle_time(presence));
385 #else
386 #error Unknown size of time_t
387 #endif
388 break;
389 case PRES_PROP_LOGIN_TIME:
390 #if SIZEOF_TIME_T == 4
391 g_value_set_int(value, purple_presence_get_login_time(presence));
392 #elif SIZEOF_TIME_T == 8
393 g_value_set_int64(value, purple_presence_get_login_time(presence));
394 #else
395 #error Unknown size of time_t
396 #endif
397 break;
398 case PRES_PROP_STATUSES:
399 g_value_set_pointer(value, purple_presence_get_statuses(presence));
400 break;
401 case PRES_PROP_ACTIVE_STATUS:
402 g_value_set_object(value, purple_presence_get_active_status(presence));
403 break;
404 default:
405 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
406 break;
410 /* GObject initialization function */
411 static void
412 purple_presence_init(PurplePresence *presence)
414 PurplePresencePrivate *priv = purple_presence_get_instance_private(presence);
415 priv->status_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
418 /* GObject dispose function */
419 static void
420 purple_presence_dispose(GObject *object)
422 PurplePresencePrivate *priv =
423 purple_presence_get_instance_private(PURPLE_PRESENCE(object));
425 if (priv->statuses) {
426 g_list_foreach(priv->statuses, (GFunc)g_object_unref, NULL);
427 g_list_free(priv->statuses);
428 priv->statuses = NULL;
431 G_OBJECT_CLASS(purple_presence_parent_class)->dispose(object);
434 /* GObject finalize function */
435 static void
436 purple_presence_finalize(GObject *object)
438 PurplePresencePrivate *priv =
439 purple_presence_get_instance_private(PURPLE_PRESENCE(object));
441 g_hash_table_destroy(priv->status_table);
443 G_OBJECT_CLASS(purple_presence_parent_class)->finalize(object);
446 /* Class initializer function */
447 static void purple_presence_class_init(PurplePresenceClass *klass)
449 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
451 obj_class->dispose = purple_presence_dispose;
452 obj_class->finalize = purple_presence_finalize;
454 /* Setup properties */
455 obj_class->get_property = purple_presence_get_property;
456 obj_class->set_property = purple_presence_set_property;
458 properties[PRES_PROP_IDLE] = g_param_spec_boolean("idle", "Idle",
459 "Whether the presence is in idle state.", FALSE,
460 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
462 properties[PRES_PROP_IDLE_TIME] =
463 #if SIZEOF_TIME_T == 4
464 g_param_spec_int
465 #elif SIZEOF_TIME_T == 8
466 g_param_spec_int64
467 #else
468 #error Unknown size of time_t
469 #endif
470 ("idle-time", "Idle time",
471 "The idle time of the presence",
472 #if SIZEOF_TIME_T == 4
473 G_MININT, G_MAXINT, 0,
474 #elif SIZEOF_TIME_T == 8
475 G_MININT64, G_MAXINT64, 0,
476 #else
477 #error Unknown size of time_t
478 #endif
479 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
481 properties[PRES_PROP_LOGIN_TIME] =
482 #if SIZEOF_TIME_T == 4
483 g_param_spec_int
484 #elif SIZEOF_TIME_T == 8
485 g_param_spec_int64
486 #else
487 #error Unknown size of time_t
488 #endif
489 ("login-time", "Login time",
490 "The login time of the presence.",
491 #if SIZEOF_TIME_T == 4
492 G_MININT, G_MAXINT, 0,
493 #elif SIZEOF_TIME_T == 8
494 G_MININT64, G_MAXINT64, 0,
495 #else
496 #error Unknown size of time_t
497 #endif
498 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
500 properties[PRES_PROP_STATUSES] = g_param_spec_pointer("statuses",
501 "Statuses",
502 "The list of statuses in the presence.",
503 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
505 properties[PRES_PROP_ACTIVE_STATUS] = g_param_spec_object("active-status",
506 "Active status",
507 "The active status for the presence.", PURPLE_TYPE_STATUS,
508 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
510 g_object_class_install_properties(obj_class, PRES_PROP_LAST, properties);
513 /**************************************************************************
514 * PurpleAccountPresence API
515 **************************************************************************/
516 static void
517 purple_account_presence_update_idle(PurplePresence *presence, gboolean old_idle)
519 PurpleAccount *account;
520 PurpleConnection *gc = NULL;
521 PurpleProtocol *protocol = NULL;
522 gboolean idle = purple_presence_is_idle(presence);
523 time_t idle_time = purple_presence_get_idle_time(presence);
524 time_t current_time = time(NULL);
526 account = purple_account_presence_get_account(PURPLE_ACCOUNT_PRESENCE(presence));
528 if (purple_prefs_get_bool("/purple/logging/log_system"))
530 PurpleLog *log = purple_account_get_log(account, FALSE);
532 if (log != NULL)
534 char *msg, *tmp;
535 GDateTime *dt;
537 if (idle) {
538 tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
539 dt = g_date_time_new_from_unix_local(idle_time);
540 } else {
541 tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
542 dt = g_date_time_new_now_utc();
545 msg = g_markup_escape_text(tmp, -1);
546 g_free(tmp);
547 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
548 purple_account_get_username(account),
549 dt, msg);
550 g_date_time_unref(dt);
551 g_free(msg);
555 gc = purple_account_get_connection(account);
557 if(PURPLE_CONNECTION_IS_CONNECTED(gc))
558 protocol = purple_connection_get_protocol(gc);
560 if (protocol)
561 purple_protocol_server_iface_set_idle(protocol, gc, (idle ? (current_time - idle_time) : 0));
564 PurpleAccount *
565 purple_account_presence_get_account(PurpleAccountPresence *presence)
567 PurpleAccountPresencePrivate *priv = purple_account_presence_get_instance_private(presence);
569 g_return_val_if_fail(priv != NULL, NULL);
571 return priv->account;
574 static int
575 purple_buddy_presence_compute_score(PurpleBuddyPresence *buddy_presence)
577 GList *l;
578 int score = 0;
579 PurplePresence *presence = PURPLE_PRESENCE(buddy_presence);
580 PurpleBuddy *b = purple_buddy_presence_get_buddy(buddy_presence);
581 int *primitive_scores = _purple_statuses_get_primitive_scores();
582 int offline_score = purple_prefs_get_int("/purple/status/scores/offline_msg");
583 int idle_score = purple_prefs_get_int("/purple/status/scores/idle");
585 for (l = purple_presence_get_statuses(presence); l != NULL; l = l->next) {
586 PurpleStatus *status = (PurpleStatus *)l->data;
587 PurpleStatusType *type = purple_status_get_status_type(status);
589 if (purple_status_is_active(status)) {
590 score += primitive_scores[purple_status_type_get_primitive(type)];
591 if (!purple_status_is_online(status)) {
592 if (b && purple_account_supports_offline_message(purple_buddy_get_account(b), b))
593 score += offline_score;
597 score += purple_account_get_int(purple_buddy_get_account(b), "score", 0);
598 if (purple_presence_is_idle(presence))
599 score += idle_score;
600 return score;
603 gint
604 purple_buddy_presence_compare(PurpleBuddyPresence *buddy_presence1,
605 PurpleBuddyPresence *buddy_presence2)
607 PurplePresence *presence1 = PURPLE_PRESENCE(buddy_presence1);
608 PurplePresence *presence2 = PURPLE_PRESENCE(buddy_presence2);
609 time_t idle_time_1, idle_time_2;
610 int score1 = 0, score2 = 0;
611 int idle_time_score = purple_prefs_get_int("/purple/status/scores/idle_time");
613 if (presence1 == presence2)
614 return 0;
615 else if (presence1 == NULL)
616 return 1;
617 else if (presence2 == NULL)
618 return -1;
620 if (purple_presence_is_online(presence1) &&
621 !purple_presence_is_online(presence2))
622 return -1;
623 else if (purple_presence_is_online(presence2) &&
624 !purple_presence_is_online(presence1))
625 return 1;
627 /* Compute the score of the first set of statuses. */
628 score1 = purple_buddy_presence_compute_score(buddy_presence1);
630 /* Compute the score of the second set of statuses. */
631 score2 = purple_buddy_presence_compute_score(buddy_presence2);
633 idle_time_1 = time(NULL) - purple_presence_get_idle_time(presence1);
634 idle_time_2 = time(NULL) - purple_presence_get_idle_time(presence2);
636 if (idle_time_1 > idle_time_2)
637 score1 += idle_time_score;
638 else if (idle_time_1 < idle_time_2)
639 score2 += idle_time_score;
641 if (score1 < score2)
642 return 1;
643 else if (score1 > score2)
644 return -1;
646 return 0;
649 /**************************************************************************
650 * GObject code for PurpleAccountPresence
651 **************************************************************************/
653 /* Set method for GObject properties */
654 static void
655 purple_account_presence_set_property(GObject *obj, guint param_id, const GValue *value,
656 GParamSpec *pspec)
658 PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj);
659 PurpleAccountPresencePrivate *priv =
660 purple_account_presence_get_instance_private(account_presence);
662 switch (param_id) {
663 case ACPRES_PROP_ACCOUNT:
664 priv->account = g_value_get_object(value);
665 break;
666 default:
667 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
668 break;
672 /* Get method for GObject properties */
673 static void
674 purple_account_presence_get_property(GObject *obj, guint param_id, GValue *value,
675 GParamSpec *pspec)
677 PurpleAccountPresence *account_presence = PURPLE_ACCOUNT_PRESENCE(obj);
679 switch (param_id) {
680 case ACPRES_PROP_ACCOUNT:
681 g_value_set_object(value,
682 purple_account_presence_get_account(account_presence));
683 break;
684 default:
685 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
686 break;
690 /* Called when done constructing */
691 static void
692 purple_account_presence_constructed(GObject *object)
694 PurplePresence *presence = PURPLE_PRESENCE(object);
695 PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence);
696 PurpleAccountPresencePrivate *account_priv =
697 purple_account_presence_get_instance_private(PURPLE_ACCOUNT_PRESENCE(presence));
699 G_OBJECT_CLASS(purple_account_presence_parent_class)->constructed(object);
701 parent_priv->statuses = purple_protocol_get_statuses(account_priv->account, presence);
704 /* Class initializer function */
705 static void purple_account_presence_class_init(PurpleAccountPresenceClass *klass)
707 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
709 PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_account_presence_update_idle;
711 obj_class->constructed = purple_account_presence_constructed;
713 /* Setup properties */
714 obj_class->get_property = purple_account_presence_get_property;
715 obj_class->set_property = purple_account_presence_set_property;
717 ap_properties[ACPRES_PROP_ACCOUNT] = g_param_spec_object("account",
718 "Account",
719 "The account that this presence is of.", PURPLE_TYPE_ACCOUNT,
720 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
721 G_PARAM_STATIC_STRINGS);
723 g_object_class_install_properties(obj_class, ACPRES_PROP_LAST,
724 ap_properties);
727 static void
728 purple_account_presence_init(PurpleAccountPresence *presence)
732 PurpleAccountPresence *
733 purple_account_presence_new(PurpleAccount *account)
735 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
737 return g_object_new(PURPLE_TYPE_ACCOUNT_PRESENCE,
738 "account", account,
739 NULL);
742 /**************************************************************************
743 * PurpleBuddyPresence API
744 **************************************************************************/
745 static void
746 purple_buddy_presence_update_idle(PurplePresence *presence, gboolean old_idle)
748 PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(presence));
749 GDateTime *current_time = g_date_time_new_now_utc();
750 PurpleBlistUiOps *ops = purple_blist_get_ui_ops();
751 PurpleAccount *account = purple_buddy_get_account(buddy);
752 gboolean idle = purple_presence_is_idle(presence);
754 if (!old_idle && idle)
756 if (purple_prefs_get_bool("/purple/logging/log_system"))
758 PurpleLog *log = purple_account_get_log(account, FALSE);
760 if (log != NULL)
762 char *tmp, *tmp2;
763 tmp = g_strdup_printf(_("%s became idle"),
764 purple_buddy_get_alias(buddy));
765 tmp2 = g_markup_escape_text(tmp, -1);
766 g_free(tmp);
768 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
769 purple_buddy_get_alias(buddy),
770 current_time, tmp2);
771 g_free(tmp2);
775 else if (old_idle && !idle)
777 if (purple_prefs_get_bool("/purple/logging/log_system"))
779 PurpleLog *log = purple_account_get_log(account, FALSE);
781 if (log != NULL)
783 char *tmp, *tmp2;
784 tmp = g_strdup_printf(_("%s became unidle"),
785 purple_buddy_get_alias(buddy));
786 tmp2 = g_markup_escape_text(tmp, -1);
787 g_free(tmp);
789 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
790 purple_buddy_get_alias(buddy),
791 current_time, tmp2);
792 g_free(tmp2);
797 if (old_idle != idle)
798 purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
799 old_idle, idle);
801 purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
803 /* Should this be done here? It'd perhaps make more sense to
804 * connect to buddy-[un]idle signals and update from there
807 if (ops != NULL && ops->update != NULL)
808 ops->update(purple_blist_get_buddy_list(), (PurpleBlistNode *)buddy);
810 g_date_time_unref(current_time);
813 PurpleBuddy *
814 purple_buddy_presence_get_buddy(PurpleBuddyPresence *presence)
816 PurpleBuddyPresencePrivate *priv = purple_buddy_presence_get_instance_private(presence);
818 g_return_val_if_fail(priv != NULL, NULL);
820 return priv->buddy;
823 /**************************************************************************
824 * GObject code for PurpleBuddyPresence
825 **************************************************************************/
827 /* Set method for GObject properties */
828 static void
829 purple_buddy_presence_set_property(GObject *obj, guint param_id, const GValue *value,
830 GParamSpec *pspec)
832 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
833 PurpleBuddyPresencePrivate *priv =
834 purple_buddy_presence_get_instance_private(buddy_presence);
836 switch (param_id) {
837 case BUDPRES_PROP_BUDDY:
838 priv->buddy = g_value_get_object(value);
839 break;
840 default:
841 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
842 break;
846 /* Get method for GObject properties */
847 static void
848 purple_buddy_presence_get_property(GObject *obj, guint param_id, GValue *value,
849 GParamSpec *pspec)
851 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
853 switch (param_id) {
854 case BUDPRES_PROP_BUDDY:
855 g_value_set_object(value,
856 purple_buddy_presence_get_buddy(buddy_presence));
857 break;
858 default:
859 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
860 break;
864 /* Called when done constructing */
865 static void
866 purple_buddy_presence_constructed(GObject *object)
868 PurplePresence *presence = PURPLE_PRESENCE(object);
869 PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence);
870 PurpleBuddyPresencePrivate *buddy_priv =
871 purple_buddy_presence_get_instance_private(PURPLE_BUDDY_PRESENCE(presence));
872 PurpleAccount *account;
874 G_OBJECT_CLASS(purple_buddy_presence_parent_class)->constructed(object);
876 account = purple_buddy_get_account(buddy_priv->buddy);
877 parent_priv->statuses = purple_protocol_get_statuses(account, presence);
880 /* Class initializer function */
881 static void purple_buddy_presence_class_init(PurpleBuddyPresenceClass *klass)
883 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
885 PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_buddy_presence_update_idle;
887 obj_class->constructed = purple_buddy_presence_constructed;
889 /* Setup properties */
890 obj_class->get_property = purple_buddy_presence_get_property;
891 obj_class->set_property = purple_buddy_presence_set_property;
893 bp_properties[BUDPRES_PROP_BUDDY] = g_param_spec_object("buddy", "Buddy",
894 "The buddy that this presence is of.", PURPLE_TYPE_BUDDY,
895 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
896 G_PARAM_STATIC_STRINGS);
898 g_object_class_install_properties(obj_class, BUDPRES_PROP_LAST,
899 bp_properties);
902 static void
903 purple_buddy_presence_init(PurpleBuddyPresence *presence)
907 PurpleBuddyPresence *
908 purple_buddy_presence_new(PurpleBuddy *buddy)
910 g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
912 return g_object_new(PURPLE_TYPE_BUDDY_PRESENCE,
913 "buddy", buddy,
914 NULL);