2 * @file purple-status.c
6 * Copyright (C) 2011-2015 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "savedstatuses.h"
28 #include "sipe-backend.h"
29 #include "sipe-core.h"
31 #include "purple-private.h"
33 guint
sipe_backend_status(struct sipe_core_public
*sipe_public
)
35 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
36 PurpleStatus
*status
= purple_account_get_active_status(purple_private
->account
);
37 if (!status
) return(SIPE_ACTIVITY_UNSET
);
38 return(sipe_purple_token_to_activity(purple_status_get_id(status
)));
41 gboolean
sipe_backend_status_changed(struct sipe_core_public
*sipe_public
,
45 gboolean result
= FALSE
;
47 if ((activity
== SIPE_ACTIVITY_AWAY
) && purple_savedstatus_is_idleaway()) {
48 SIPE_DEBUG_INFO_NOFORMAT("sipe_backend_status_changed: user is already idle-away");
50 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
51 PurpleStatus
*status
= purple_account_get_active_status(purple_private
->account
);
52 const gchar
*status_id
= sipe_purple_activity_to_token(activity
);
54 result
= !(g_str_equal(status_id
, purple_status_get_id(status
)) &&
55 sipe_strequal(message
,
56 purple_status_get_attr_string(status
,
57 SIPE_PURPLE_STATUS_ATTR_ID_MESSAGE
)));
64 * This method motivates Purple's Host (e.g. Pidgin) to update its UI
65 * by using standard Purple's means of signals and saved statuses.
67 * Thus all UI elements get updated: Status Button with Note, docklet.
68 * This is ablolutely important as both our status and note can come
69 * inbound (roaming) or be updated programmatically (e.g. based on our
72 void sipe_backend_status_and_note(struct sipe_core_public
*sipe_public
,
76 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
77 PurpleAccount
*account
= purple_private
->account
;
78 const gchar
*status_id
= sipe_purple_activity_to_token(activity
);
79 PurpleSavedStatus
*saved_status
;
80 const PurpleStatusType
*acct_status_type
=
81 purple_status_type_find_with_id(purple_account_get_status_types(account
),
83 PurpleStatusPrimitive primitive
= purple_status_type_get_primitive(acct_status_type
);
85 /* code adapted from: pidgin/gtkstatusbox.c */
86 saved_status
= purple_savedstatus_find_transient_by_type_and_message(primitive
, message
);
88 purple_savedstatus_set_substatus(saved_status
, account
, acct_status_type
, message
);
90 /* This type+message is unique then create a new transient saved status */
92 GList
*active_accts
= purple_accounts_get_all_active();
94 SIPE_DEBUG_INFO("sipe_backend_status_and_note: creating new saved status %s '%s'",
95 status_id
, message
? message
: "(null)");
97 saved_status
= purple_savedstatus_new(NULL
, primitive
);
98 purple_savedstatus_set_message(saved_status
, message
);
100 for (entry
= active_accts
; entry
!= NULL
; entry
= entry
->next
)
101 purple_savedstatus_set_substatus(saved_status
,
102 (PurpleAccount
*) entry
->data
,
105 g_list_free(active_accts
);
108 /* Set the status for each account */
109 purple_private
->status_changed_by_core
= TRUE
;
110 purple_savedstatus_activate(saved_status
);
114 * Work around broken libpurple idle notification
116 * (1) user changes the status
117 * sipe_purple_set_status()
118 * -> user changed state
120 * (2) client detects that user is idle
121 * sipe_purple_set_status() [sometimes omitted?!?!?]
122 * sipe_purple_set_idle( != 0 )
123 * -> machine changed state
125 * (3) client detects that user is no longer idle
126 * sipe_purple_set_idle(0)
127 * sipe_purple_set_status()
128 * -> user changed state
130 * (4) core sends a status change
131 * sipe_backend_status_and_note()
132 * purple_savedstatus_activate()
133 * sipe_purple_set_status()
134 * -> status change must be ignored
136 * Cases (1) and (2) can only be differentiated by deferring the update.
138 static void sipe_purple_status_deferred_update(struct sipe_backend_private
*purple_private
,
139 gboolean changed_by_user
)
141 gchar
*note
= purple_private
->deferred_status_note
;
143 purple_private
->deferred_status_note
= NULL
;
144 purple_private
->deferred_status_timeout
= 0;
146 sipe_core_status_set(purple_private
->public,
148 purple_private
->deferred_status_activity
,
153 static gboolean
sipe_purple_status_timeout(gpointer data
)
155 /* timeout expired -> no idle indication -> state changed by user */
156 sipe_purple_status_deferred_update(data
, TRUE
);
160 void sipe_purple_set_status(PurpleAccount
*account
,
161 PurpleStatus
*status
)
163 if (purple_account_get_connection(account
) &&
164 purple_status_is_active(status
)) {
165 struct sipe_core_public
*sipe_public
= PURPLE_ACCOUNT_TO_SIPE_CORE_PUBLIC
;
166 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
167 const gchar
*status_id
= purple_status_get_id(status
);
168 guint activity
= sipe_purple_token_to_activity(status_id
);
169 const gchar
*note
= purple_status_get_attr_string(status
,
170 SIPE_PURPLE_STATUS_ATTR_ID_MESSAGE
);
172 SIPE_DEBUG_INFO("sipe_purple_set_status[CB]: '%s'",
175 if (purple_private
->status_changed_by_core
) {
176 SIPE_DEBUG_INFO_NOFORMAT("sipe_purple_set_status[CB]: triggered by core - ignoring");
178 } else if (purple_private
->user_is_not_idle
) {
179 sipe_core_status_set(sipe_public
,
185 if (purple_private
->deferred_status_timeout
)
186 purple_timeout_remove(purple_private
->deferred_status_timeout
);
187 g_free(purple_private
->deferred_status_note
);
189 SIPE_DEBUG_INFO_NOFORMAT("sipe_purple_set_status[CB]: defer status update");
191 purple_private
->deferred_status_note
= g_strdup(note
);
192 purple_private
->deferred_status_activity
= activity
;
193 purple_private
->deferred_status_timeout
= purple_timeout_add_seconds(1,
194 sipe_purple_status_timeout
,
199 purple_private
->status_changed_by_core
= FALSE
;
200 purple_private
->user_is_not_idle
= FALSE
;
204 void sipe_purple_set_idle(PurpleConnection
*gc
,
208 struct sipe_core_public
*sipe_public
= PURPLE_GC_TO_SIPE_CORE_PUBLIC
;
209 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
211 purple_private
->user_is_not_idle
= interval
== 0;
213 SIPE_DEBUG_INFO("sipe_purple_set_idle[CB]: user is %sidle",
214 purple_private
->user_is_not_idle
? "not " : "");
216 if (!purple_private
->user_is_not_idle
) {
217 /* timeout not expired -> state changed by machine */
218 if (purple_private
->deferred_status_timeout
)
219 purple_timeout_remove(purple_private
->deferred_status_timeout
);
220 sipe_purple_status_deferred_update(purple_private
, FALSE
);