Add support to get PMF information
[platform/upstream/connman.git] / src / clock.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2013  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 <sys/time.h>
27
28 #include <gdbus.h>
29
30 #include "connman.h"
31
32 enum timezone_updates {
33         TIMEZONE_UPDATES_UNKNOWN = 0,
34         TIMEZONE_UPDATES_MANUAL  = 1,
35         TIMEZONE_UPDATES_AUTO    = 2,
36 };
37
38 static enum time_updates time_updates_config = TIME_UPDATES_AUTO;
39 static enum timezone_updates timezone_updates_config = TIMEZONE_UPDATES_AUTO;
40
41 static char *timezone_config = NULL;
42 #if defined TIZEN_EXT
43 static bool time_updated = false;
44 #endif
45
46 static const char *time_updates2string(enum time_updates value)
47 {
48         switch (value) {
49         case TIME_UPDATES_UNKNOWN:
50                 break;
51         case TIME_UPDATES_MANUAL:
52                 return "manual";
53         case TIME_UPDATES_AUTO:
54                 return "auto";
55         }
56
57         return NULL;
58 }
59
60 static enum time_updates string2time_updates(const char *value)
61 {
62         if (g_strcmp0(value, "manual") == 0)
63                 return TIME_UPDATES_MANUAL;
64         else if (g_strcmp0(value, "auto") == 0)
65                 return TIME_UPDATES_AUTO;
66
67         return TIME_UPDATES_UNKNOWN;
68 }
69
70 static const char *timezone_updates2string(enum timezone_updates value)
71 {
72         switch (value) {
73         case TIMEZONE_UPDATES_UNKNOWN:
74                 break;
75         case TIMEZONE_UPDATES_MANUAL:
76                 return "manual";
77         case TIMEZONE_UPDATES_AUTO:
78                 return "auto";
79         }
80
81         return NULL;
82 }
83
84 static enum timezone_updates string2timezone_updates(const char *value)
85 {
86         if (g_strcmp0(value, "manual") == 0)
87                 return TIMEZONE_UPDATES_MANUAL;
88         else if (g_strcmp0(value, "auto") == 0)
89                 return TIMEZONE_UPDATES_AUTO;
90
91         return TIMEZONE_UPDATES_UNKNOWN;
92 }
93
94 static void clock_properties_load(void)
95 {
96         GKeyFile *keyfile;
97         char *str;
98         enum time_updates time_value;
99         enum timezone_updates timezone_value;
100
101         keyfile = __connman_storage_load_global();
102         if (!keyfile)
103                 return;
104
105         str = g_key_file_get_string(keyfile, "global", "TimeUpdates", NULL);
106
107         time_value = string2time_updates(str);
108         if (time_value != TIME_UPDATES_UNKNOWN)
109                 time_updates_config = time_value;
110
111         g_free(str);
112
113         str = g_key_file_get_string(keyfile, "global", "TimezoneUpdates",
114                         NULL);
115
116         timezone_value = string2timezone_updates(str);
117         if (timezone_value != TIMEZONE_UPDATES_UNKNOWN)
118                 timezone_updates_config = timezone_value;
119
120         g_free(str);
121
122         g_key_file_free(keyfile);
123 }
124
125 static void clock_properties_save(void)
126 {
127         GKeyFile *keyfile;
128         const char *str;
129
130         keyfile = __connman_storage_load_global();
131         if (!keyfile)
132                 keyfile = g_key_file_new();
133
134         str = time_updates2string(time_updates_config);
135         if (str)
136                 g_key_file_set_string(keyfile, "global", "TimeUpdates", str);
137         else
138                 g_key_file_remove_key(keyfile, "global", "TimeUpdates", NULL);
139
140         str = timezone_updates2string(timezone_updates_config);
141         if (str)
142                 g_key_file_set_string(keyfile, "global", "TimezoneUpdates",
143                                 str);
144         else
145                 g_key_file_remove_key(keyfile, "global", "TimezoneUpdates",
146                                 NULL);
147
148         __connman_storage_save_global(keyfile);
149
150         g_key_file_free(keyfile);
151 }
152
153 enum time_updates __connman_clock_timeupdates(void)
154 {
155         return time_updates_config;
156 }
157
158 static void append_timeservers(DBusMessageIter *iter, void *user_data)
159 {
160         int i;
161         char **timeservers = __connman_timeserver_system_get();
162
163         if (!timeservers)
164                 return;
165
166         for (i = 0; timeservers[i]; i++) {
167                 dbus_message_iter_append_basic(iter,
168                                 DBUS_TYPE_STRING, &timeservers[i]);
169         }
170
171         g_strfreev(timeservers);
172 }
173
174 static DBusMessage *get_properties(DBusConnection *conn,
175                                         DBusMessage *msg, void *data)
176 {
177         DBusMessage *reply;
178         DBusMessageIter array, dict;
179         struct timeval tv;
180         const char *str;
181 #if defined TIZEN_EXT
182         dbus_bool_t val = time_updated;
183 #endif
184
185         DBG("conn %p", conn);
186
187         reply = dbus_message_new_method_return(msg);
188         if (!reply)
189                 return NULL;
190
191         dbus_message_iter_init_append(reply, &array);
192
193         connman_dbus_dict_open(&array, &dict);
194
195 #if defined TIZEN_EXT
196         connman_dbus_dict_append_basic(&dict, "TimeUpdated",
197                                                 DBUS_TYPE_BOOLEAN,
198                                                 &val);
199 #endif
200
201         if (gettimeofday(&tv, NULL) == 0) {
202                 dbus_uint64_t val = tv.tv_sec;
203
204                 connman_dbus_dict_append_basic(&dict, "Time",
205                                                 DBUS_TYPE_UINT64, &val);
206         }
207
208         str = time_updates2string(time_updates_config);
209         if (str)
210                 connman_dbus_dict_append_basic(&dict, "TimeUpdates",
211                                                 DBUS_TYPE_STRING, &str);
212
213         if (timezone_config)
214                 connman_dbus_dict_append_basic(&dict, "Timezone",
215                                         DBUS_TYPE_STRING, &timezone_config);
216
217         str = timezone_updates2string(timezone_updates_config);
218         if (str)
219                 connman_dbus_dict_append_basic(&dict, "TimezoneUpdates",
220                                                 DBUS_TYPE_STRING, &str);
221
222         connman_dbus_dict_append_array(&dict, "Timeservers",
223                                 DBUS_TYPE_STRING, append_timeservers, NULL);
224
225         connman_dbus_dict_close(&array, &dict);
226
227         return reply;
228 }
229
230 static DBusMessage *set_property(DBusConnection *conn,
231                                         DBusMessage *msg, void *data)
232 {
233         DBusMessageIter iter, value;
234         const char *name;
235         int type;
236
237         DBG("conn %p", conn);
238
239         if (!dbus_message_iter_init(msg, &iter))
240                 return __connman_error_invalid_arguments(msg);
241
242         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
243                 return __connman_error_invalid_arguments(msg);
244
245         dbus_message_iter_get_basic(&iter, &name);
246         dbus_message_iter_next(&iter);
247
248         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
249                 return __connman_error_invalid_arguments(msg);
250
251         dbus_message_iter_recurse(&iter, &value);
252
253         type = dbus_message_iter_get_arg_type(&value);
254
255         if (g_str_equal(name, "Time")) {
256 #if defined TIZEN_EXT
257                 /* Tizen updates time (ntp) by system service */
258
259                 return __connman_error_permission_denied(msg);
260 #else
261                 struct timeval tv;
262                 dbus_uint64_t newval;
263
264                 if (type != DBUS_TYPE_UINT64)
265                         return __connman_error_invalid_arguments(msg);
266
267                 if (time_updates_config != TIME_UPDATES_MANUAL)
268                         return __connman_error_permission_denied(msg);
269
270                 dbus_message_iter_get_basic(&value, &newval);
271
272                 tv.tv_sec = newval;
273                 tv.tv_usec = 0;
274
275                 if (settimeofday(&tv, NULL) < 0)
276                         return __connman_error_invalid_arguments(msg);
277
278                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
279                                 CONNMAN_CLOCK_INTERFACE, "Time",
280                                 DBUS_TYPE_UINT64, &newval);
281 #endif
282         } else if (g_str_equal(name, "TimeUpdates")) {
283                 const char *strval;
284                 enum time_updates newval;
285
286                 if (type != DBUS_TYPE_STRING)
287                         return __connman_error_invalid_arguments(msg);
288
289                 dbus_message_iter_get_basic(&value, &strval);
290                 newval = string2time_updates(strval);
291
292                 if (newval == TIME_UPDATES_UNKNOWN)
293                         return __connman_error_invalid_arguments(msg);
294
295                 if (newval == time_updates_config)
296                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
297
298                 time_updates_config = newval;
299
300                 clock_properties_save();
301                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
302                                 CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
303                                 DBUS_TYPE_STRING, &strval);
304         } else if (g_str_equal(name, "Timezone")) {
305                 const char *strval;
306
307                 if (type != DBUS_TYPE_STRING)
308                         return __connman_error_invalid_arguments(msg);
309
310                 if (timezone_updates_config != TIMEZONE_UPDATES_MANUAL)
311                         return __connman_error_permission_denied(msg);
312
313                 dbus_message_iter_get_basic(&value, &strval);
314
315                 if (__connman_timezone_change(strval) < 0)
316                         return __connman_error_invalid_arguments(msg);
317         } else if (g_str_equal(name, "TimezoneUpdates")) {
318                 const char *strval;
319                 enum timezone_updates newval;
320
321                 if (type != DBUS_TYPE_STRING)
322                         return __connman_error_invalid_arguments(msg);
323
324                 dbus_message_iter_get_basic(&value, &strval);
325                 newval = string2timezone_updates(strval);
326
327                 if (newval == TIMEZONE_UPDATES_UNKNOWN)
328                         return __connman_error_invalid_arguments(msg);
329
330                 if (newval == timezone_updates_config)
331                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
332
333                 timezone_updates_config = newval;
334
335                 clock_properties_save();
336                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
337                                 CONNMAN_CLOCK_INTERFACE, "TimezoneUpdates",
338                                 DBUS_TYPE_STRING, &strval);
339         } else if (g_str_equal(name, "Timeservers")) {
340                 DBusMessageIter entry;
341                 char **str = NULL;
342                 GSList *list = NULL;
343                 int count = 0;
344
345                 if (type != DBUS_TYPE_ARRAY)
346                         return __connman_error_invalid_arguments(msg);
347
348                 dbus_message_iter_recurse(&value, &entry);
349
350                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
351                         const char *val;
352                         GSList *new_head;
353
354                         dbus_message_iter_get_basic(&entry, &val);
355
356                         new_head = __connman_timeserver_add_list(list, val);
357                         if (list != new_head) {
358                                 count++;
359                                 list = new_head;
360                         }
361
362                         dbus_message_iter_next(&entry);
363                 }
364
365                 if (list) {
366                         str = g_new0(char *, count+1);
367
368                         while (list) {
369                                 count--;
370                                 str[count] = list->data;
371                                 list = g_slist_delete_link(list, list);
372                         };
373                 }
374
375                 __connman_timeserver_system_set(str);
376
377                 if (str)
378                         g_strfreev(str);
379
380                 connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
381                                 CONNMAN_CLOCK_INTERFACE, "Timeservers",
382                                 DBUS_TYPE_STRING, append_timeservers, NULL);
383         } else
384                 return __connman_error_invalid_property(msg);
385
386         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
387 }
388
389 static const GDBusMethodTable clock_methods[] = {
390         { GDBUS_METHOD("GetProperties",
391                         NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
392                         get_properties) },
393         { GDBUS_METHOD("SetProperty",
394                         GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
395                         set_property)   },
396         { },
397 };
398
399 static const GDBusSignalTable clock_signals[] = {
400         { GDBUS_SIGNAL("PropertyChanged",
401                         GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
402         { },
403 };
404
405 static DBusConnection *connection = NULL;
406
407 #if defined TIZEN_EXT
408 void __connman_clock_set_time_updated(bool updated)
409 {
410         time_updated = updated;
411 }
412 #endif
413
414 void __connman_clock_update_timezone(void)
415 {
416         DBG("");
417
418         g_free(timezone_config);
419         timezone_config = __connman_timezone_lookup();
420
421         if (!timezone_config)
422                 return;
423
424         connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
425                                 CONNMAN_CLOCK_INTERFACE, "Timezone",
426                                 DBUS_TYPE_STRING, &timezone_config);
427 }
428
429 int __connman_clock_init(void)
430 {
431         DBG("");
432
433         connection = connman_dbus_get_connection();
434         if (!connection)
435                 return -1;
436
437         __connman_timezone_init();
438
439         timezone_config = __connman_timezone_lookup();
440
441         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
442                                                 CONNMAN_CLOCK_INTERFACE,
443                                                 clock_methods, clock_signals,
444                                                 NULL, NULL, NULL);
445
446         clock_properties_load();
447         return 0;
448 }
449
450 void __connman_clock_cleanup(void)
451 {
452         DBG("");
453
454         if (!connection)
455                 return;
456
457         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
458                                                 CONNMAN_CLOCK_INTERFACE);
459
460         dbus_connection_unref(connection);
461
462         __connman_timezone_cleanup();
463
464         g_free(timezone_config);
465 }