don't start GPS when there is no working connection
[azimuth] / src / connection-watcher.c
1 /*
2  * connection-watcher.c - Source for ConnectionWatcher
3  * Copyright (C) 2010 Guillaume Desmottes
4  * @author Guillaume Desmottes <gdesmott@gnome.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <telepathy-glib/account-manager.h>
26 #include <telepathy-glib/account.h>
27 #include <telepathy-glib/dbus.h>
28 #include <telepathy-glib/interfaces.h>
29 #include <telepathy-glib/gtypes.h>
30 #include <telepathy-glib/util.h>
31
32 #include "connection-watcher.h"
33
34 G_DEFINE_TYPE(ConnectionWatcher, connection_watcher, G_TYPE_OBJECT)
35
36 /* signal enum */
37 enum
38 {
39     CONNECTION_ADDED,
40     LAST_SIGNAL
41 };
42
43 static guint signals[LAST_SIGNAL] = {0};
44
45 /* private structure */
46 typedef struct _ConnectionWatcherPrivate ConnectionWatcherPrivate;
47
48 struct _ConnectionWatcherPrivate
49 {
50   TpAccountManager *account_mgr;
51   TpDBusDaemon *bus_daemon;
52   GList *accounts;
53
54   gboolean dispose_has_run;
55 };
56
57 #define CONNECTION_WATCHER_GET_PRIVATE(o)     (G_TYPE_INSTANCE_GET_PRIVATE ((o), CONNECTION_WATCHER_TYPE, ConnectionWatcherPrivate))
58
59 static void
60 connection_watcher_init (ConnectionWatcher *obj)
61 {
62   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (obj);
63
64   priv->bus_daemon = tp_dbus_daemon_dup (NULL);
65   g_assert (priv->bus_daemon != NULL);
66
67   priv->account_mgr = tp_account_manager_new (priv->bus_daemon);
68   priv->accounts = NULL;
69 }
70
71 static void connection_watcher_dispose (GObject *object);
72 static void connection_watcher_finalize (GObject *object);
73
74 static void account_invalidated_cb (TpProxy *proxy,
75     guint domain,
76     gint code,
77     gchar *message,
78     gpointer user_data);
79
80 static void
81 connection_watcher_class_init (ConnectionWatcherClass *connection_watcher_class)
82 {
83   GObjectClass *object_class = G_OBJECT_CLASS (connection_watcher_class);
84
85   g_type_class_add_private (connection_watcher_class, sizeof (ConnectionWatcherPrivate));
86
87   object_class->dispose = connection_watcher_dispose;
88   object_class->finalize = connection_watcher_finalize;
89
90   signals[CONNECTION_ADDED] = g_signal_new ("connection-added",
91     G_TYPE_FROM_CLASS (object_class),
92     G_SIGNAL_RUN_LAST,
93     0, NULL, NULL,
94     g_cclosure_marshal_VOID__OBJECT,
95     G_TYPE_NONE, 1, TP_TYPE_CONNECTION);
96 }
97
98 void
99 connection_watcher_dispose (GObject *object)
100 {
101   ConnectionWatcher *self = CONNECTION_WATCHER (object);
102   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
103   GList *l;
104
105   if (priv->dispose_has_run)
106     return;
107
108   priv->dispose_has_run = TRUE;
109
110   g_object_unref (priv->account_mgr);
111
112   for (l = priv->accounts; l != NULL; l = g_list_next (l))
113     {
114       g_signal_handlers_disconnect_by_func (l->data, account_invalidated_cb,
115           self);
116       g_object_unref (l->data);
117     }
118
119   g_object_unref (priv->bus_daemon);
120
121   if (G_OBJECT_CLASS (connection_watcher_parent_class)->dispose)
122     G_OBJECT_CLASS (connection_watcher_parent_class)->dispose (object);
123 }
124
125 void
126 connection_watcher_finalize (GObject *object)
127 {
128   ConnectionWatcher *self = CONNECTION_WATCHER (object);
129   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
130
131   g_list_free (priv->accounts);
132
133   G_OBJECT_CLASS (connection_watcher_parent_class)->finalize (object);
134 }
135
136 ConnectionWatcher *
137 connection_watcher_new (void)
138 {
139   return g_object_new (CONNECTION_WATCHER_TYPE,
140       NULL);
141 }
142
143 static void
144 conn_ready_cb (TpConnection *conn,
145     const GError *error,
146     gpointer user_data)
147 {
148   ConnectionWatcher *self = CONNECTION_WATCHER (user_data);
149
150   if (error != NULL)
151     {
152       g_print ("connection is not ready: %s\n", error->message);
153       goto out;
154     }
155
156   g_signal_emit (self, signals[CONNECTION_ADDED], 0, conn);
157
158 out:
159   g_object_unref (conn);
160 }
161
162 static void
163 account_invalidated_cb (TpProxy *proxy,
164     guint domain,
165     gint code,
166     gchar *message,
167     gpointer user_data)
168 {
169   ConnectionWatcher *self = CONNECTION_WATCHER (user_data);
170   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
171
172   g_print ("remove invalidated account: %s\n",
173       tp_proxy_get_object_path (proxy));
174
175   priv->accounts = g_list_remove (priv->accounts, proxy);
176   g_object_unref (proxy);
177 }
178
179 static void
180 create_connection (ConnectionWatcher *self,
181     const gchar *path)
182 {
183   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
184   TpConnection *conn;
185   GError *err = NULL;
186
187   if (path == NULL || !tp_strdiff (path, "/"))
188     return;
189
190   conn = tp_connection_new (priv->bus_daemon, NULL, path, &err);
191   if (conn == NULL)
192     {
193       g_print ("Failed to create TpConnection: %s\n", err->message);
194       g_error_free (err);
195       return;
196     }
197
198   tp_connection_call_when_ready (conn, conn_ready_cb, self);
199 }
200
201 static void
202 get_connection_cb (TpProxy *account,
203     const GValue *out_Value,
204     const GError *error,
205     gpointer user_data,
206     GObject *weak_object)
207 {
208   ConnectionWatcher *self = CONNECTION_WATCHER (weak_object);
209   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
210
211   if (error != NULL)
212     {
213       g_print ("Failed to fetch Connection property: %s\n", error->message);
214       priv->accounts = g_list_remove (priv->accounts, account);
215       g_object_unref (account);
216       return;
217     }
218
219   create_connection (self, g_value_get_boxed (out_Value));
220 }
221
222 static void
223 account_property_changed_cb (TpAccount *account,
224     GHashTable *properties,
225     gpointer user_data,
226     GObject *weak_object)
227 {
228   ConnectionWatcher *self = CONNECTION_WATCHER (weak_object);
229
230   create_connection (self, tp_asv_get_object_path (properties, "Connection"));
231 }
232
233 static void
234 add_account (ConnectionWatcher *self,
235     TpAccount *account)
236 {
237   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
238
239   priv->accounts = g_list_prepend (priv->accounts, account);
240
241   tp_cli_dbus_properties_call_get (account, -1,
242       TP_IFACE_ACCOUNT, "Connection", get_connection_cb,
243       self, NULL, G_OBJECT (self));
244
245   tp_cli_account_connect_to_account_property_changed (account,
246       account_property_changed_cb, self, NULL, G_OBJECT (self), NULL);
247
248   g_signal_connect (account, "invalidated",
249       G_CALLBACK (account_invalidated_cb), self);
250 }
251
252 static void
253 account_validity_changed_cb (TpAccountManager *account_mgr,
254     const gchar *account_path,
255     gboolean valid,
256     gpointer user_data,
257     GObject *weak_object)
258 {
259   ConnectionWatcher *self = CONNECTION_WATCHER (weak_object);
260   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
261   GError *err = NULL;
262   TpAccount *account;
263
264   account = tp_account_new (priv->bus_daemon, account_path, &err);
265   if (account == NULL)
266     {
267       g_print ("Failed to create TpAccount: %s\n", err->message);
268       g_error_free (err);
269       return;
270     }
271
272   if (g_list_find (priv->accounts, account) != NULL)
273     return;
274
275   add_account (self, account);
276 }
277
278 static void
279 get_valid_accounts_cb (TpProxy *proxy,
280     const GValue *out_Value,
281     const GError *error,
282     gpointer user_data,
283     GObject *weak_object)
284 {
285   ConnectionWatcher *self = CONNECTION_WATCHER (weak_object);
286   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
287   GPtrArray *valid_accounts;
288   guint i;
289
290   if (error != NULL)
291     {
292       g_print ("Failed to fetch ValidAccounts property: %s\n", error->message);
293       return;
294     }
295
296   valid_accounts = g_value_get_boxed (out_Value);
297   if (valid_accounts == NULL)
298     return;
299
300   for (i = 0; i < valid_accounts->len; i++)
301     {
302       const gchar *name;
303       TpAccount *account;
304       GError *err = NULL;
305
306       name = g_ptr_array_index (valid_accounts, i);
307       account = tp_account_new (priv->bus_daemon, name, &err);
308       if (account == NULL)
309         {
310           g_print ("Failed to create TpAccount: %s\n", err->message);
311           g_error_free (err);
312           continue;
313         }
314
315       add_account (self, account);
316     }
317 }
318
319 void
320 connection_watcher_start (ConnectionWatcher *self)
321 {
322   ConnectionWatcherPrivate *priv = CONNECTION_WATCHER_GET_PRIVATE (self);
323
324   tp_cli_dbus_properties_call_get (priv->account_mgr, -1,
325       TP_IFACE_ACCOUNT_MANAGER, "ValidAccounts", get_valid_accounts_cb,
326       self, NULL, G_OBJECT (self));
327
328   tp_cli_account_manager_connect_to_account_validity_changed (priv->account_mgr,
329       account_validity_changed_cb, NULL, NULL, G_OBJECT (self), NULL);
330 }