mark PurpleImageClass as private
[pidgin-git.git] / libpurple / presence.c
blob35c2f518fcecec3b46ac15e2fcaaca1501e1c563
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_foreach(priv->statuses, (GFunc)g_object_unref, NULL);
466 g_list_free(priv->statuses);
467 priv->statuses = NULL;
470 G_OBJECT_CLASS(purple_presence_parent_class)->dispose(object);
473 /* GObject finalize function */
474 static void
475 purple_presence_finalize(GObject *object)
477 PurplePresencePrivate *priv =
478 purple_presence_get_instance_private(PURPLE_PRESENCE(object));
480 g_hash_table_destroy(priv->status_table);
482 G_OBJECT_CLASS(purple_presence_parent_class)->finalize(object);
485 /* Class initializer function */
486 static void purple_presence_class_init(PurplePresenceClass *klass)
488 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
490 obj_class->dispose = purple_presence_dispose;
491 obj_class->finalize = purple_presence_finalize;
493 /* Setup properties */
494 obj_class->get_property = purple_presence_get_property;
495 obj_class->set_property = purple_presence_set_property;
497 properties[PRES_PROP_IDLE] = g_param_spec_boolean("idle", "Idle",
498 "Whether the presence is in idle state.", FALSE,
499 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
501 properties[PRES_PROP_IDLE_TIME] =
502 #if SIZEOF_TIME_T == 4
503 g_param_spec_int
504 #elif SIZEOF_TIME_T == 8
505 g_param_spec_int64
506 #else
507 #error Unknown size of time_t
508 #endif
509 ("idle-time", "Idle time",
510 "The idle time of the presence",
511 #if SIZEOF_TIME_T == 4
512 G_MININT, G_MAXINT, 0,
513 #elif SIZEOF_TIME_T == 8
514 G_MININT64, G_MAXINT64, 0,
515 #else
516 #error Unknown size of time_t
517 #endif
518 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
520 properties[PRES_PROP_LOGIN_TIME] =
521 #if SIZEOF_TIME_T == 4
522 g_param_spec_int
523 #elif SIZEOF_TIME_T == 8
524 g_param_spec_int64
525 #else
526 #error Unknown size of time_t
527 #endif
528 ("login-time", "Login time",
529 "The login time of the presence.",
530 #if SIZEOF_TIME_T == 4
531 G_MININT, G_MAXINT, 0,
532 #elif SIZEOF_TIME_T == 8
533 G_MININT64, G_MAXINT64, 0,
534 #else
535 #error Unknown size of time_t
536 #endif
537 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
539 properties[PRES_PROP_STATUSES] = g_param_spec_pointer("statuses",
540 "Statuses",
541 "The list of statuses in the presence.",
542 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
544 properties[PRES_PROP_ACTIVE_STATUS] = g_param_spec_object("active-status",
545 "Active status",
546 "The active status for the presence.", PURPLE_TYPE_STATUS,
547 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
549 g_object_class_install_properties(obj_class, PRES_PROP_LAST, properties);
552 /**************************************************************************
553 * PurpleAccountPresence API
554 **************************************************************************/
555 static void
556 purple_account_presence_update_idle(PurplePresence *presence, gboolean old_idle)
558 PurpleAccount *account;
559 PurpleConnection *gc = NULL;
560 PurpleProtocol *protocol = NULL;
561 gboolean idle = purple_presence_is_idle(presence);
562 time_t idle_time = purple_presence_get_idle_time(presence);
563 time_t current_time = time(NULL);
565 account = purple_account_presence_get_account(PURPLE_ACCOUNT_PRESENCE(presence));
567 if (purple_prefs_get_bool("/purple/logging/log_system"))
569 PurpleLog *log = purple_account_get_log(account, FALSE);
571 if (log != NULL)
573 char *msg, *tmp;
574 GDateTime *dt;
576 if (idle) {
577 tmp = g_strdup_printf(_("+++ %s became idle"), purple_account_get_username(account));
578 dt = g_date_time_new_from_unix_local(idle_time);
579 } else {
580 tmp = g_strdup_printf(_("+++ %s became unidle"), purple_account_get_username(account));
581 dt = g_date_time_new_now_utc();
584 msg = g_markup_escape_text(tmp, -1);
585 g_free(tmp);
586 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
587 purple_account_get_username(account),
588 dt, msg);
589 g_date_time_unref(dt);
590 g_free(msg);
594 gc = purple_account_get_connection(account);
596 if(PURPLE_CONNECTION_IS_CONNECTED(gc))
597 protocol = purple_connection_get_protocol(gc);
599 if (protocol)
600 purple_protocol_server_iface_set_idle(protocol, gc, (idle ? (current_time - idle_time) : 0));
603 PurpleAccount *
604 purple_account_presence_get_account(PurpleAccountPresence *presence)
606 PurpleAccountPresencePrivate *priv = NULL;
608 g_return_val_if_fail(PURPLE_IS_ACCOUNT_PRESENCE(presence), NULL);
610 priv = purple_account_presence_get_instance_private(presence);
611 return priv->account;
614 static int
615 purple_buddy_presence_compute_score(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(PurpleBuddyPresence *buddy_presence1,
645 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_instance_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 PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence);
736 PurpleAccountPresencePrivate *account_priv =
737 purple_account_presence_get_instance_private(PURPLE_ACCOUNT_PRESENCE(presence));
739 G_OBJECT_CLASS(purple_account_presence_parent_class)->constructed(object);
741 parent_priv->statuses = purple_protocol_get_statuses(account_priv->account, presence);
744 /* Class initializer function */
745 static void purple_account_presence_class_init(PurpleAccountPresenceClass *klass)
747 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
749 PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_account_presence_update_idle;
751 obj_class->constructed = purple_account_presence_constructed;
753 /* Setup properties */
754 obj_class->get_property = purple_account_presence_get_property;
755 obj_class->set_property = purple_account_presence_set_property;
757 ap_properties[ACPRES_PROP_ACCOUNT] = g_param_spec_object("account",
758 "Account",
759 "The account that this presence is of.", PURPLE_TYPE_ACCOUNT,
760 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
761 G_PARAM_STATIC_STRINGS);
763 g_object_class_install_properties(obj_class, ACPRES_PROP_LAST,
764 ap_properties);
767 static void
768 purple_account_presence_init(PurpleAccountPresence *presence)
772 PurpleAccountPresence *
773 purple_account_presence_new(PurpleAccount *account)
775 g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
777 return g_object_new(PURPLE_TYPE_ACCOUNT_PRESENCE,
778 "account", account,
779 NULL);
782 /**************************************************************************
783 * PurpleBuddyPresence API
784 **************************************************************************/
785 static void
786 purple_buddy_presence_update_idle(PurplePresence *presence, gboolean old_idle)
788 PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(presence));
789 GDateTime *current_time = g_date_time_new_now_utc();
790 PurpleAccount *account = purple_buddy_get_account(buddy);
791 gboolean idle = purple_presence_is_idle(presence);
793 if (!old_idle && idle)
795 if (purple_prefs_get_bool("/purple/logging/log_system"))
797 PurpleLog *log = purple_account_get_log(account, FALSE);
799 if (log != NULL)
801 char *tmp, *tmp2;
802 tmp = g_strdup_printf(_("%s became idle"),
803 purple_buddy_get_alias(buddy));
804 tmp2 = g_markup_escape_text(tmp, -1);
805 g_free(tmp);
807 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
808 purple_buddy_get_alias(buddy),
809 current_time, tmp2);
810 g_free(tmp2);
814 else if (old_idle && !idle)
816 if (purple_prefs_get_bool("/purple/logging/log_system"))
818 PurpleLog *log = purple_account_get_log(account, FALSE);
820 if (log != NULL)
822 char *tmp, *tmp2;
823 tmp = g_strdup_printf(_("%s became unidle"),
824 purple_buddy_get_alias(buddy));
825 tmp2 = g_markup_escape_text(tmp, -1);
826 g_free(tmp);
828 purple_log_write(log, PURPLE_MESSAGE_SYSTEM,
829 purple_buddy_get_alias(buddy),
830 current_time, tmp2);
831 g_free(tmp2);
836 if (old_idle != idle)
837 purple_signal_emit(purple_blist_get_handle(), "buddy-idle-changed", buddy,
838 old_idle, idle);
840 purple_contact_invalidate_priority_buddy(purple_buddy_get_contact(buddy));
842 /* Should this be done here? It'd perhaps make more sense to
843 * connect to buddy-[un]idle signals and update from there
846 purple_blist_update_node(purple_blist_get_default(),
847 PURPLE_BLIST_NODE(buddy));
849 g_date_time_unref(current_time);
852 PurpleBuddy *
853 purple_buddy_presence_get_buddy(PurpleBuddyPresence *presence)
855 PurpleBuddyPresencePrivate *priv = NULL;
857 g_return_val_if_fail(PURPLE_IS_BUDDY_PRESENCE(presence), NULL);
859 priv = purple_buddy_presence_get_instance_private(presence);
860 return priv->buddy;
863 /**************************************************************************
864 * GObject code for PurpleBuddyPresence
865 **************************************************************************/
867 /* Set method for GObject properties */
868 static void
869 purple_buddy_presence_set_property(GObject *obj, guint param_id, const GValue *value,
870 GParamSpec *pspec)
872 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
873 PurpleBuddyPresencePrivate *priv =
874 purple_buddy_presence_get_instance_private(buddy_presence);
876 switch (param_id) {
877 case BUDPRES_PROP_BUDDY:
878 priv->buddy = g_value_get_object(value);
879 break;
880 default:
881 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
882 break;
886 /* Get method for GObject properties */
887 static void
888 purple_buddy_presence_get_property(GObject *obj, guint param_id, GValue *value,
889 GParamSpec *pspec)
891 PurpleBuddyPresence *buddy_presence = PURPLE_BUDDY_PRESENCE(obj);
893 switch (param_id) {
894 case BUDPRES_PROP_BUDDY:
895 g_value_set_object(value,
896 purple_buddy_presence_get_buddy(buddy_presence));
897 break;
898 default:
899 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
900 break;
904 /* Called when done constructing */
905 static void
906 purple_buddy_presence_constructed(GObject *object)
908 PurplePresence *presence = PURPLE_PRESENCE(object);
909 PurplePresencePrivate *parent_priv = purple_presence_get_instance_private(presence);
910 PurpleBuddyPresencePrivate *buddy_priv =
911 purple_buddy_presence_get_instance_private(PURPLE_BUDDY_PRESENCE(presence));
912 PurpleAccount *account;
914 G_OBJECT_CLASS(purple_buddy_presence_parent_class)->constructed(object);
916 account = purple_buddy_get_account(buddy_priv->buddy);
917 parent_priv->statuses = purple_protocol_get_statuses(account, presence);
920 /* Class initializer function */
921 static void purple_buddy_presence_class_init(PurpleBuddyPresenceClass *klass)
923 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
925 PURPLE_PRESENCE_CLASS(klass)->update_idle = purple_buddy_presence_update_idle;
927 obj_class->constructed = purple_buddy_presence_constructed;
929 /* Setup properties */
930 obj_class->get_property = purple_buddy_presence_get_property;
931 obj_class->set_property = purple_buddy_presence_set_property;
933 bp_properties[BUDPRES_PROP_BUDDY] = g_param_spec_object("buddy", "Buddy",
934 "The buddy that this presence is of.", PURPLE_TYPE_BUDDY,
935 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
936 G_PARAM_STATIC_STRINGS);
938 g_object_class_install_properties(obj_class, BUDPRES_PROP_LAST,
939 bp_properties);
942 static void
943 purple_buddy_presence_init(PurpleBuddyPresence *presence)
947 PurpleBuddyPresence *
948 purple_buddy_presence_new(PurpleBuddy *buddy)
950 g_return_val_if_fail(PURPLE_IS_BUDDY(buddy), NULL);
952 return g_object_new(PURPLE_TYPE_BUDDY_PRESENCE,
953 "buddy", buddy,
954 NULL);