a8c56ffc8dbea6b2e6c9baba811ed98de0cd0d36
[connman] / src / profile.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2009  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program 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
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <glib.h>
27 #include <gdbus.h>
28
29 #include "connman.h"
30
31 #define PROFILE_DEFAULT  "/profile/default"
32
33 enum connman_service_state {
34         CONNMAN_SERVICE_STATE_UNKNOWN = 0,
35         CONNMAN_SERVICE_STATE_IDLE    = 1,
36 };
37
38 struct connman_group {
39         GSequenceIter *iter;
40         char *id;
41         char *path;
42         char *type;
43         char *name;
44         char *mode;
45         char *security;
46         connman_uint8_t strength;
47         connman_bool_t favorite;
48         enum connman_service_state state;
49         struct connman_network *network;
50 };
51
52 static GSequence *groups = NULL;
53
54 static DBusConnection *connection = NULL;
55
56 static const char *state2string(enum connman_service_state state)
57 {
58         switch (state) {
59         case CONNMAN_SERVICE_STATE_UNKNOWN:
60                 break;
61         case CONNMAN_SERVICE_STATE_IDLE:
62                 return "idle";
63         }
64
65         return NULL;
66 }
67
68 static DBusMessage *get_properties(DBusConnection *conn,
69                                         DBusMessage *msg, void *data)
70 {
71         struct connman_group *group = data;
72         DBusMessage *reply;
73         DBusMessageIter array, dict;
74         const char *str;
75
76         DBG("conn %p", conn);
77
78         reply = dbus_message_new_method_return(msg);
79         if (reply == NULL)
80                 return NULL;
81
82         dbus_message_iter_init_append(reply, &array);
83
84         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
85                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
86                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
87                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
88
89         str = state2string(group->state);
90         if (str != NULL)
91                 connman_dbus_dict_append_variant(&dict, "State",
92                                                 DBUS_TYPE_STRING, &str);
93
94         if (group->type != NULL)
95                 connman_dbus_dict_append_variant(&dict, "Type",
96                                         DBUS_TYPE_STRING, &group->type);
97
98         if (group->name != NULL)
99                 connman_dbus_dict_append_variant(&dict, "Name",
100                                         DBUS_TYPE_STRING, &group->name);
101
102         if (group->mode != NULL)
103                 connman_dbus_dict_append_variant(&dict, "Mode",
104                                         DBUS_TYPE_STRING, &group->mode);
105
106         if (group->security != NULL)
107                 connman_dbus_dict_append_variant(&dict, "Security",
108                                         DBUS_TYPE_STRING, &group->security);
109
110         if (group->strength > 0)
111                 connman_dbus_dict_append_variant(&dict, "Strength",
112                                         DBUS_TYPE_BYTE, &group->strength);
113
114         connman_dbus_dict_append_variant(&dict, "Favorite",
115                                         DBUS_TYPE_BOOLEAN, &group->favorite);
116
117         dbus_message_iter_close_container(&array, &dict);
118
119         return reply;
120 }
121
122 static DBusMessage *connect_service(DBusConnection *conn,
123                                         DBusMessage *msg, void *data)
124 {
125         return __connman_error_not_implemented(msg);
126 }
127
128 static DBusMessage *disconnect_service(DBusConnection *conn,
129                                         DBusMessage *msg, void *data)
130 {
131         return __connman_error_not_implemented(msg);
132 }
133
134 static DBusMessage *remove_service(DBusConnection *conn,
135                                         DBusMessage *msg, void *data)
136 {
137         return __connman_error_not_implemented(msg);
138 }
139
140 static DBusMessage *move_before(DBusConnection *conn,
141                                         DBusMessage *msg, void *data)
142 {
143         return __connman_error_not_implemented(msg);
144 }
145
146 static DBusMessage *move_after(DBusConnection *conn,
147                                         DBusMessage *msg, void *data)
148 {
149         return __connman_error_not_implemented(msg);
150 }
151
152 static GDBusMethodTable service_methods[] = {
153         { "GetProperties", "",  "a{sv}", get_properties     },
154         { "Connect",       "",  "",      connect_service    },
155         { "Disconnect",    "",  "",      disconnect_service },
156         { "Remove",        "",  "",      remove_service     },
157         { "MoveBefore",    "o", "",      move_before        },
158         { "MoveAfter",     "o", "",      move_after         },
159         { },
160 };
161
162 static GDBusSignalTable service_signals[] = {
163         { "PropertyChanged", "sv" },
164         { },
165 };
166
167 static void free_group(gpointer data)
168 {
169         struct connman_group *group = data;
170
171         DBG("group %p", group);
172
173         g_dbus_unregister_interface(connection, group->path,
174                                                 CONNMAN_SERVICE_INTERFACE);
175
176         g_free(group->security);
177         g_free(group->mode);
178         g_free(group->name);
179         g_free(group->type);
180         g_free(group->path);
181         g_free(group->id);
182         g_free(group);
183 }
184
185 static gint compare_group(gconstpointer a, gconstpointer b, gpointer user_data)
186 {
187         struct connman_group *group_a = (void *) a;
188         struct connman_group *group_b = (void *) b;
189
190         if (group_a->favorite == TRUE && group_b->favorite == FALSE)
191                 return -1;
192
193         if (group_a->favorite == FALSE && group_b->favorite == TRUE)
194                 return 1;
195
196         return (gint) group_b->strength - (gint) group_a->strength;
197 }
198
199 static gint search_group(gconstpointer a, gconstpointer b, gpointer user_data)
200 {
201         struct connman_group *group = (void *) a;
202
203         return g_strcmp0(group->id, user_data);
204 }
205
206 static struct connman_group *lookup_group(const char *name)
207 {
208         GSequenceIter *iter;
209         struct connman_group *group;
210
211         DBG("name %s", name);
212
213         if (name == NULL)
214                 return NULL;
215
216         iter = g_sequence_search(groups, NULL, search_group, (char *) name);
217         if (g_sequence_iter_is_begin(iter) == FALSE &&
218                                 g_sequence_iter_is_end(iter) == FALSE) {
219                 group = g_sequence_get(iter);
220                 if (group != NULL)
221                         goto done;
222         }
223
224         group = g_try_new0(struct connman_group, 1);
225         if (group == NULL)
226                 return NULL;
227
228         group->id = g_strdup(name);
229
230         group->type = CONNMAN_ELEMENT_TYPE_UNKNOWN;
231         group->path = g_strdup_printf("%s/%s", PROFILE_DEFAULT, name);
232
233         group->favorite = FALSE;
234
235         group->state = CONNMAN_SERVICE_STATE_IDLE;
236
237         group->iter = g_sequence_insert_sorted(groups, group,
238                                                 compare_group, NULL);
239
240         g_dbus_register_interface(connection, group->path,
241                                         CONNMAN_SERVICE_INTERFACE,
242                                         service_methods, service_signals,
243                                                         NULL, group, NULL);
244
245 done:
246         DBG("group %p", group);
247
248         return group;
249 }
250
251 int __connman_profile_add_device(struct connman_device *device)
252 {
253         struct connman_group *group;
254         char *name;
255
256         DBG("device %p", device);
257
258         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
259                                         connman_device_get_index(device));
260         group = lookup_group(name);
261         g_free(name);
262
263         if (group == NULL)
264                 return -EINVAL;
265
266         group->type = g_strdup(__connman_device_get_type(device));
267
268         g_sequence_sort_changed(group->iter, compare_group, NULL);
269
270         return 0;
271 }
272
273 int __connman_profile_remove_device(struct connman_device *device)
274 {
275         struct connman_group *group;
276         char *name;
277
278         DBG("device %p", device);
279
280         name = g_strdup_printf("%s_%d", __connman_device_get_type(device),
281                                         connman_device_get_index(device));
282         group = lookup_group(name);
283         g_free(name);
284
285         if (group == NULL)
286                 return -EINVAL;
287
288         g_free(group->type);
289         group->type = NULL;
290
291         g_sequence_sort_changed(group->iter, compare_group, NULL);
292
293         return 0;
294 }
295
296 int __connman_profile_add_network(struct connman_network *network)
297 {
298         struct connman_group *group;
299         char *name;
300
301         DBG("network %p", network);
302
303         if (__connman_network_get_group(network) == NULL)
304                 return -EINVAL;
305
306         name = g_strdup_printf("%s_%s", __connman_network_get_type(network),
307                                         __connman_network_get_group(network));
308         group = lookup_group(name);
309         g_free(name);
310
311         if (group == NULL)
312                 return -EINVAL;
313
314         g_free(group->type);
315         g_free(group->name);
316
317         group->type = g_strdup(__connman_network_get_type(network));
318         group->name = g_strdup(connman_network_get_string(network, "Name"));
319
320         group->strength = connman_network_get_uint8(network, "Strength");
321
322         if (group->network == NULL) {
323                 group->network = network;
324
325                 group->mode = g_strdup(connman_network_get_string(network,
326                                                                 "WiFi.Mode"));
327                 group->security = g_strdup(connman_network_get_string(network,
328                                                         "WiFi.Security"));
329         }
330
331         g_sequence_sort_changed(group->iter, compare_group, NULL);
332
333         return 0;
334 }
335
336 int __connman_profile_remove_network(struct connman_network *network)
337 {
338         struct connman_group *group;
339         char *name;
340
341         DBG("network %p", network);
342
343         if (__connman_network_get_group(network) == NULL)
344                 return -EINVAL;
345
346         name = g_strdup_printf("%s_%s", __connman_network_get_type(network),
347                                         __connman_network_get_group(network));
348         group = lookup_group(name);
349         g_free(name);
350
351         if (group == NULL)
352                 return -EINVAL;
353
354         if (group->network == network) {
355                 g_free(group->security);
356                 group->security = NULL;
357
358                 g_free(group->mode);
359                 group->mode = NULL;
360
361                 group->network = NULL;
362         }
363
364         g_free(group->type);
365         group->type = NULL;
366
367         g_sequence_sort_changed(group->iter, compare_group, NULL);
368
369         return 0;
370 }
371
372 const char *__connman_profile_active(void)
373 {
374         DBG("");
375
376         return PROFILE_DEFAULT;
377 }
378
379 void __connman_profile_list(DBusMessageIter *iter)
380 {
381         const char *path = __connman_profile_active();
382
383         DBG("");
384
385         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
386 }
387
388 static void append_path(gpointer value, gpointer user_data)
389 {
390         struct connman_group *group = value;
391         DBusMessageIter *iter = user_data;
392
393         dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
394                                                         &group->path);
395 }
396
397 void __connman_profile_list_services(DBusMessageIter *iter)
398 {
399         DBG("");
400
401         g_sequence_foreach(groups, append_path, iter);
402 }
403
404 static void append_services(DBusMessageIter *dict)
405 {
406         DBusMessageIter entry, value, iter;
407         const char *key = "Services";
408
409         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
410                                                                 NULL, &entry);
411
412         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
413
414         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
415                 DBUS_TYPE_ARRAY_AS_STRING DBUS_TYPE_OBJECT_PATH_AS_STRING,
416                                                                 &value);
417
418         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
419                                 DBUS_TYPE_OBJECT_PATH_AS_STRING, &iter);
420         __connman_profile_list_services(&iter);
421         dbus_message_iter_close_container(&value, &iter);
422
423         dbus_message_iter_close_container(&entry, &value);
424
425         dbus_message_iter_close_container(dict, &entry);
426 }
427
428 static DBusMessage *profile_properties(DBusConnection *conn,
429                                         DBusMessage *msg, void *data)
430 {
431         const char *name = "Default";
432         DBusMessage *reply;
433         DBusMessageIter array, dict;
434
435         DBG("conn %p", conn);
436
437         reply = dbus_message_new_method_return(msg);
438         if (reply == NULL)
439                 return NULL;
440
441         dbus_message_iter_init_append(reply, &array);
442
443         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY,
444                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
445                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
446                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
447
448         connman_dbus_dict_append_variant(&dict, "Name",
449                                                 DBUS_TYPE_STRING, &name);
450
451         append_services(&dict);
452
453         dbus_message_iter_close_container(&array, &dict);
454
455         return reply;
456 }
457
458 static GDBusMethodTable profile_methods[] = {
459         { "GetProperties", "", "a{sv}", profile_properties },
460         { },
461 };
462
463 int __connman_profile_init(DBusConnection *conn)
464 {
465         DBG("conn %p", conn);
466
467         connection = dbus_connection_ref(conn);
468         if (connection == NULL)
469                 return -1;
470
471         groups = g_sequence_new(free_group);
472
473         g_dbus_register_interface(connection, PROFILE_DEFAULT,
474                                                 CONNMAN_PROFILE_INTERFACE,
475                                                 profile_methods,
476                                                 NULL, NULL, NULL, NULL);
477
478         return 0;
479 }
480
481 void __connman_profile_cleanup(void)
482 {
483         DBG("conn %p", connection);
484
485         g_dbus_unregister_interface(connection, PROFILE_DEFAULT,
486                                                 CONNMAN_PROFILE_INTERFACE);
487
488         g_sequence_free(groups);
489         groups = NULL;
490
491         if (connection == NULL)
492                 return;
493
494         dbus_connection_unref(connection);
495 }