]> git.0d.be Git - empathy.git/blob - libempathy/empathy-idle.c
Do not load avatar from cache if token is empty. Fixes bug #517098.
[empathy.git] / libempathy / empathy-idle.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  * 
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <glib/gi18n.h>
27 #include <dbus/dbus-glib.h>
28
29 #include <libtelepathy/tp-helpers.h>
30 #include <libmissioncontrol/mc-enum-types.h>
31
32 #include "empathy-idle.h"
33 #include "empathy-utils.h" 
34 #include "empathy-debug.h"
35
36 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
37                        EMPATHY_TYPE_IDLE, EmpathyIdlePriv))
38
39 #define DEBUG_DOMAIN "Idle"
40
41 /* Number of seconds before entering extended autoaway. */
42 #define EXT_AWAY_TIME (30*60)
43
44 typedef enum {
45         NM_STATE_UNKNOWN,
46         NM_STATE_ASLEEP,
47         NM_STATE_CONNECTING,
48         NM_STATE_CONNECTED,
49         NM_STATE_DISCONNECTED
50 } NMState;
51
52 struct _EmpathyIdlePriv {
53         MissionControl *mc;
54         DBusGProxy     *gs_proxy;
55         DBusGProxy     *nm_proxy;
56
57         McPresence      state;
58         gchar          *status;
59         McPresence      flash_state;
60         gboolean        auto_away;
61         gboolean        use_nm;
62
63         gboolean        away_reset_status;
64         McPresence      away_saved_state;
65         gboolean        nm_reset_status;
66         McPresence      nm_saved_state;
67
68         gboolean        is_idle;
69         gboolean        nm_connected;
70         guint           ext_away_timeout;
71 };
72
73 static void     empathy_idle_class_init      (EmpathyIdleClass *klass);
74 static void     empathy_idle_init            (EmpathyIdle      *idle);
75 static void     idle_finalize                (GObject          *object);
76 static void     idle_get_property            (GObject          *object,
77                                               guint             param_id,
78                                               GValue           *value,
79                                               GParamSpec       *pspec);
80 static void     idle_set_property            (GObject          *object,
81                                               guint             param_id,
82                                               const GValue     *value,
83                                               GParamSpec       *pspec);
84 static void     idle_presence_changed_cb     (MissionControl   *mc,
85                                               McPresence        state,
86                                               gchar            *status,
87                                               EmpathyIdle      *idle);
88 static void     idle_session_idle_changed_cb (DBusGProxy       *gs_proxy,
89                                               gboolean          is_idle,
90                                               EmpathyIdle      *idle);
91 static void     idle_nm_state_change_cb      (DBusGProxy       *proxy,
92                                               guint             state,
93                                               EmpathyIdle      *idle);
94 static void     idle_ext_away_start          (EmpathyIdle      *idle);
95 static void     idle_ext_away_stop           (EmpathyIdle      *idle);
96 static gboolean idle_ext_away_cb             (EmpathyIdle      *idle);
97
98 enum {
99         PROP_0,
100         PROP_STATE,
101         PROP_STATUS,
102         PROP_FLASH_STATE,
103         PROP_AUTO_AWAY,
104         PROP_USE_NM
105 };
106
107 G_DEFINE_TYPE (EmpathyIdle, empathy_idle, G_TYPE_OBJECT)
108
109 static void
110 empathy_idle_class_init (EmpathyIdleClass *klass)
111 {
112         GObjectClass *object_class = G_OBJECT_CLASS (klass);
113
114         object_class->finalize = idle_finalize;
115         object_class->get_property = idle_get_property;
116         object_class->set_property = idle_set_property;
117
118         g_object_class_install_property (object_class,
119                                          PROP_STATE,
120                                          g_param_spec_enum ("state",
121                                                             "state",
122                                                             "state",
123                                                             MC_TYPE_PRESENCE,
124                                                             MC_PRESENCE_AVAILABLE,
125                                                             G_PARAM_READWRITE));
126         g_object_class_install_property (object_class,
127                                          PROP_STATUS,
128                                          g_param_spec_string ("status",
129                                                               "status",
130                                                               "status",
131                                                               NULL,
132                                                               G_PARAM_READWRITE));
133         g_object_class_install_property (object_class,
134                                          PROP_FLASH_STATE,
135                                          g_param_spec_enum ("flash-state",
136                                                             "flash-state",
137                                                             "flash-state",
138                                                             MC_TYPE_PRESENCE,
139                                                             MC_PRESENCE_UNSET,
140                                                             G_PARAM_READWRITE));
141
142          g_object_class_install_property (object_class,
143                                           PROP_AUTO_AWAY,
144                                           g_param_spec_boolean ("auto-away",
145                                                                 "Automatic set presence to away",
146                                                                 "Should it set presence to away if inactive",
147                                                                 FALSE,
148                                                                 G_PARAM_READWRITE));
149
150          g_object_class_install_property (object_class,
151                                           PROP_USE_NM,
152                                           g_param_spec_boolean ("use-nm",
153                                                                 "Use Network Manager",
154                                                                 "Set presence according to Network Manager",
155                                                                 FALSE,
156                                                                 G_PARAM_READWRITE));
157
158         g_type_class_add_private (object_class, sizeof (EmpathyIdlePriv));
159 }
160
161 static void
162 empathy_idle_init (EmpathyIdle *idle)
163 {
164         EmpathyIdlePriv *priv;
165         DBusGConnection *system_bus;
166         GError          *error = NULL;
167
168         priv = GET_PRIV (idle);
169
170         priv->is_idle = FALSE;
171         priv->mc = empathy_mission_control_new ();
172         priv->state = mission_control_get_presence_actual (priv->mc, NULL);
173         priv->status = mission_control_get_presence_message_actual (priv->mc, NULL);
174
175         dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
176                                      "PresenceChanged",
177                                      G_CALLBACK (idle_presence_changed_cb),
178                                      idle, NULL);
179
180         priv->gs_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
181                                                     "org.gnome.ScreenSaver",
182                                                     "/org/gnome/ScreenSaver",
183                                                     "org.gnome.ScreenSaver");
184         if (priv->gs_proxy) {
185                 dbus_g_proxy_add_signal (priv->gs_proxy, "SessionIdleChanged",
186                                          G_TYPE_BOOLEAN,
187                                          G_TYPE_INVALID);
188                 dbus_g_proxy_connect_signal (priv->gs_proxy, "SessionIdleChanged",
189                                              G_CALLBACK (idle_session_idle_changed_cb),
190                                              idle, NULL);
191         } else {
192                 empathy_debug (DEBUG_DOMAIN, "Failed to get gs proxy");
193         }
194
195
196         system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
197         if (!system_bus) {
198                 empathy_debug (DEBUG_DOMAIN, "Failed to get system bus: %s",
199                               error ? error->message : "No error given");
200         } else {
201                 priv->nm_proxy = dbus_g_proxy_new_for_name (system_bus,
202                                                             "org.freedesktop.NetworkManager",
203                                                             "/org/freedesktop/NetworkManager",
204                                                             "org.freedesktop.NetworkManager");
205         }
206         if (priv->nm_proxy) {
207                 dbus_g_proxy_add_signal (priv->nm_proxy, "StateChange",
208                                          G_TYPE_UINT, G_TYPE_INVALID);
209                 dbus_g_proxy_connect_signal (priv->nm_proxy, "StateChange",
210                                              G_CALLBACK (idle_nm_state_change_cb),
211                                              idle, NULL);
212         } else {
213                 empathy_debug (DEBUG_DOMAIN, "Failed to get nm proxy");
214         }
215
216         priv->nm_connected = TRUE;
217 }
218
219 static void
220 idle_finalize (GObject *object)
221 {
222         EmpathyIdlePriv *priv;
223
224         priv = GET_PRIV (object);
225
226         g_free (priv->status);
227         g_object_unref (priv->mc);
228
229         if (priv->gs_proxy) {
230                 g_object_unref (priv->gs_proxy);
231         }
232
233         idle_ext_away_stop (EMPATHY_IDLE (object));
234 }
235
236 static void
237 idle_get_property (GObject    *object,
238                    guint       param_id,
239                    GValue     *value,
240                    GParamSpec *pspec)
241 {
242         EmpathyIdlePriv *priv;
243         EmpathyIdle     *idle;
244
245         priv = GET_PRIV (object);
246         idle = EMPATHY_IDLE (object);
247
248         switch (param_id) {
249         case PROP_STATE:
250                 g_value_set_enum (value, empathy_idle_get_state (idle));
251                 break;
252         case PROP_STATUS:
253                 g_value_set_string (value, empathy_idle_get_status (idle));
254                 break;
255         case PROP_FLASH_STATE:
256                 g_value_set_enum (value, empathy_idle_get_flash_state (idle));
257                 break;
258         case PROP_AUTO_AWAY:
259                 g_value_set_boolean (value, empathy_idle_get_auto_away (idle));
260                 break;
261         case PROP_USE_NM:
262                 g_value_set_boolean (value, empathy_idle_get_use_nm (idle));
263                 break;
264         default:
265                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
266                 break;
267         };
268 }
269
270 static void
271 idle_set_property (GObject      *object,
272                    guint         param_id,
273                    const GValue *value,
274                    GParamSpec   *pspec)
275 {
276         EmpathyIdlePriv *priv;
277         EmpathyIdle     *idle;
278
279         priv = GET_PRIV (object);
280         idle = EMPATHY_IDLE (object);
281
282         switch (param_id) {
283         case PROP_STATE:
284                 empathy_idle_set_state (idle, g_value_get_enum (value));
285                 break;
286         case PROP_STATUS:
287                 empathy_idle_set_status (idle, g_value_get_string (value));
288                 break;
289         case PROP_FLASH_STATE:
290                 empathy_idle_set_flash_state (idle, g_value_get_enum (value));
291                 break;
292         case PROP_AUTO_AWAY:
293                 empathy_idle_set_auto_away (idle, g_value_get_boolean (value));
294                 break;
295         case PROP_USE_NM:
296                 empathy_idle_set_use_nm (idle, g_value_get_boolean (value));
297                 break;
298         default:
299                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
300                 break;
301         };
302 }
303
304 EmpathyIdle *
305 empathy_idle_new (void)
306 {
307         static EmpathyIdle *idle = NULL;
308
309         if (!idle) {
310                 idle = g_object_new (EMPATHY_TYPE_IDLE, NULL);
311                 g_object_add_weak_pointer (G_OBJECT (idle), (gpointer) &idle);
312         } else {
313                 g_object_ref (idle);
314         }
315
316         return idle;
317 }
318
319 McPresence
320 empathy_idle_get_state (EmpathyIdle *idle)
321 {
322         EmpathyIdlePriv *priv;
323
324         priv = GET_PRIV (idle);
325
326         return priv->state;
327 }
328
329 void
330 empathy_idle_set_state (EmpathyIdle *idle,
331                         McPresence   state)
332 {
333         EmpathyIdlePriv *priv;
334
335         priv = GET_PRIV (idle);
336
337         empathy_idle_set_presence (idle, state, priv->status);
338 }
339
340 const gchar *
341 empathy_idle_get_status (EmpathyIdle *idle)
342 {
343         EmpathyIdlePriv *priv;
344
345         priv = GET_PRIV (idle);
346
347         if (!priv->status) {
348                 return empathy_presence_get_default_message (priv->state);
349         }
350
351         return priv->status;
352 }
353
354 void
355 empathy_idle_set_status (EmpathyIdle *idle,
356                          const gchar *status)
357 {
358         EmpathyIdlePriv *priv;
359
360         priv = GET_PRIV (idle);
361
362         empathy_idle_set_presence (idle, priv->state, status);
363 }
364
365 McPresence
366 empathy_idle_get_flash_state (EmpathyIdle *idle)
367 {
368         EmpathyIdlePriv *priv;
369
370         priv = GET_PRIV (idle);
371
372         return priv->flash_state;
373 }
374
375 void
376 empathy_idle_set_flash_state (EmpathyIdle *idle,
377                               McPresence   state)
378 {
379         EmpathyIdlePriv *priv;
380
381         priv = GET_PRIV (idle);
382
383         priv->flash_state = state;
384
385         if (state == MC_PRESENCE_UNSET) {
386         }
387
388         g_object_notify (G_OBJECT (idle), "flash-state");
389 }
390
391 void
392 empathy_idle_set_presence (EmpathyIdle *idle,
393                            McPresence   state,
394                            const gchar *status)
395 {
396         EmpathyIdlePriv *priv;
397         const gchar     *default_status;
398
399         priv = GET_PRIV (idle);
400
401         empathy_debug (DEBUG_DOMAIN, "Changing presence to %s (%d)",
402                        status, state);
403
404         if (!priv->nm_connected) {
405                 empathy_debug (DEBUG_DOMAIN, "NM not connected");
406                 return;
407         }
408
409         /* Do not set translated default messages */
410         default_status = empathy_presence_get_default_message (state);
411         if (status && strcmp (status, default_status) == 0) {
412                 status = NULL;
413         }
414
415         mission_control_set_presence (priv->mc,
416                                       state,
417                                       status,
418                                       NULL, NULL);
419 }
420
421 gboolean
422 empathy_idle_get_auto_away (EmpathyIdle *idle)
423 {
424         EmpathyIdlePriv *priv = GET_PRIV (idle);
425
426         return priv->auto_away;
427 }
428
429 void
430 empathy_idle_set_auto_away (EmpathyIdle *idle,
431                             gboolean     auto_away)
432 {
433         EmpathyIdlePriv *priv = GET_PRIV (idle);
434
435         priv->auto_away = auto_away;
436
437         g_object_notify (G_OBJECT (idle), "auto-away");
438 }
439
440 gboolean
441 empathy_idle_get_use_nm (EmpathyIdle *idle)
442 {
443         EmpathyIdlePriv *priv = GET_PRIV (idle);
444
445         return priv->use_nm;
446 }
447
448 void
449 empathy_idle_set_use_nm (EmpathyIdle *idle,
450                          gboolean     use_nm)
451 {
452         EmpathyIdlePriv *priv = GET_PRIV (idle);
453
454         if (!priv->nm_proxy || use_nm == priv->use_nm) {
455                 return;
456         }
457
458         priv->use_nm = use_nm;
459
460         if (use_nm) {
461                 guint   nm_status;
462                 GError *error = NULL;
463
464                 dbus_g_proxy_call (priv->nm_proxy, "state",
465                                    &error,
466                                    G_TYPE_INVALID,
467                                    G_TYPE_UINT, &nm_status,
468                                    G_TYPE_INVALID);
469
470                 if (error) {
471                         empathy_debug (DEBUG_DOMAIN, 
472                                        "Couldn't get NM state: %s",
473                                        error->message);
474                         g_clear_error (&error);
475                         nm_status = NM_STATE_ASLEEP;
476                 }
477                 
478                 idle_nm_state_change_cb (priv->nm_proxy, nm_status, idle);
479         } else {
480                 if (!priv->nm_connected) {
481                         empathy_idle_set_state (idle, priv->nm_saved_state);
482                 }
483                 priv->nm_connected = TRUE;
484                 priv->nm_saved_state = MC_PRESENCE_UNSET;
485         }
486
487         g_object_notify (G_OBJECT (idle), "use-nm");
488 }
489
490 static void
491 idle_presence_changed_cb (MissionControl *mc,
492                           McPresence      state,
493                           gchar          *status,
494                           EmpathyIdle    *idle)
495 {
496         EmpathyIdlePriv *priv;
497
498         priv = GET_PRIV (idle);
499
500         empathy_debug (DEBUG_DOMAIN, "Presence changed to '%s' (%d)",
501                        status, state);
502
503         g_free (priv->status);
504         priv->state = state;
505         priv->status = NULL;
506         if (!G_STR_EMPTY (status)) {
507                 priv->status = g_strdup (status);
508         }
509
510         g_object_notify (G_OBJECT (idle), "state");
511         g_object_notify (G_OBJECT (idle), "status");
512 }
513
514 static void
515 idle_session_idle_changed_cb (DBusGProxy  *gs_proxy,
516                               gboolean     is_idle,
517                               EmpathyIdle *idle)
518 {
519         EmpathyIdlePriv *priv;
520
521         priv = GET_PRIV (idle);
522
523         empathy_debug (DEBUG_DOMAIN, "Session idle state changed, %s -> %s",
524                       priv->is_idle ? "yes" : "no",
525                       is_idle ? "yes" : "no");
526
527         if (priv->state <= MC_PRESENCE_OFFLINE ||
528             priv->state == MC_PRESENCE_HIDDEN ||
529             !priv->auto_away) {
530                 /* We are not online or we don't want to go auto away,
531                  * nothing to do here */
532                 priv->is_idle = is_idle;
533                 return;
534         }
535
536         if (is_idle && !priv->is_idle) {
537                 McPresence new_state;
538                 /* We are now idle */
539
540                 if (priv->state == MC_PRESENCE_AWAY ||
541                     priv->state == MC_PRESENCE_EXTENDED_AWAY) {
542                         /* User set away manually, when coming back we restore
543                          * default presence. */
544                         new_state = priv->state;
545                         priv->away_saved_state = MC_PRESENCE_AVAILABLE;
546                         priv->away_reset_status = TRUE;
547                 } else {
548                         new_state = MC_PRESENCE_AWAY;
549                         priv->away_saved_state = priv->state;
550                         priv->away_reset_status = FALSE;
551                 }
552
553                 empathy_debug (DEBUG_DOMAIN, "Going to autoaway");
554                 empathy_idle_set_state (idle, new_state);
555
556                 idle_ext_away_start (idle);
557         } else if (!is_idle && priv->is_idle) {
558                 /* We are no more idle, restore state */
559                 idle_ext_away_stop (idle);
560
561                 empathy_debug (DEBUG_DOMAIN, "Restoring state to %d, reset status: %s",
562                               priv->away_saved_state,
563                               priv->away_reset_status ? "Yes" : "No");
564
565                 if (priv->nm_connected) {
566                         empathy_idle_set_presence (idle,
567                                                    priv->away_saved_state,
568                                                    priv->away_reset_status ? NULL : priv->status);
569                 } else {
570                         /* We can't restore state now, will do when NM gets
571                          * connected. */
572                         priv->nm_saved_state = priv->away_saved_state;
573                         priv->nm_reset_status = priv->away_reset_status;
574                 }
575
576                 priv->away_saved_state = MC_PRESENCE_UNSET;
577                 priv->away_reset_status = FALSE;
578         }
579
580         priv->is_idle = is_idle;
581 }
582
583 static void
584 idle_nm_state_change_cb (DBusGProxy  *proxy,
585                          guint        state,
586                          EmpathyIdle *idle)
587 {
588         EmpathyIdlePriv *priv;
589         gboolean         old_nm_connected;
590         gboolean         new_nm_connected;
591
592         priv = GET_PRIV (idle);
593
594         empathy_debug (DEBUG_DOMAIN, "New network state (%d), in use = %s",
595                        state, priv->use_nm ? "Yes" : "No");
596
597         if (!priv->use_nm) {
598                 return;
599         }
600
601         old_nm_connected = priv->nm_connected;
602         new_nm_connected = !(state == NM_STATE_CONNECTING ||
603                              state == NM_STATE_DISCONNECTED);
604         priv->nm_connected = TRUE; /* To be sure _set_state will work */
605
606         if (old_nm_connected && !new_nm_connected) {
607                 /* We are no more connected */
608                 idle_ext_away_stop (idle);
609
610                 priv->nm_saved_state = priv->state;
611                 empathy_idle_set_state (idle, MC_PRESENCE_OFFLINE);
612         }
613         else if (!old_nm_connected && new_nm_connected) {
614                 /* We are now connected */
615                 empathy_idle_set_presence (idle,
616                                            priv->nm_saved_state,
617                                            priv->nm_reset_status ? NULL : priv->status);
618                 priv->nm_saved_state = MC_PRESENCE_UNSET;
619                 priv->nm_reset_status = FALSE;
620         }
621
622         priv->nm_connected = new_nm_connected;
623 }
624
625 static void
626 idle_ext_away_start (EmpathyIdle *idle)
627 {
628         EmpathyIdlePriv *priv;
629
630         priv = GET_PRIV (idle);
631
632         idle_ext_away_stop (idle);
633         priv->ext_away_timeout = g_timeout_add_seconds (EXT_AWAY_TIME,
634                                                         (GSourceFunc) idle_ext_away_cb,
635                                                         idle);
636 }
637
638 static void
639 idle_ext_away_stop (EmpathyIdle *idle)
640 {
641         EmpathyIdlePriv *priv;
642
643         priv = GET_PRIV (idle);
644
645         if (priv->ext_away_timeout) {
646                 g_source_remove (priv->ext_away_timeout);
647                 priv->ext_away_timeout = 0;
648         }
649 }
650
651 static gboolean
652 idle_ext_away_cb (EmpathyIdle *idle)
653 {
654         EmpathyIdlePriv *priv;
655
656         priv = GET_PRIV (idle);
657
658         empathy_debug (DEBUG_DOMAIN, "Going to extended autoaway");
659         empathy_idle_set_state (idle, MC_PRESENCE_EXTENDED_AWAY);
660         priv->ext_away_timeout = 0;
661
662         return FALSE;
663 }
664