clock: Emit property changed signal when time property is channged.
[platform/upstream/connman.git] / src / clock.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2007-2010  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 time_updates {
33         TIME_UPDATES_UNKNOWN = 0,
34         TIME_UPDATES_MANUAL  = 1,
35         TIME_UPDATES_AUTO    = 2,
36 };
37
38 enum timezone_updates {
39         TIMEZONE_UPDATES_UNKNOWN = 0,
40         TIMEZONE_UPDATES_MANUAL  = 1,
41         TIMEZONE_UPDATES_AUTO    = 2,
42 };
43
44 static enum time_updates time_updates_config = TIME_UPDATES_AUTO;
45 static enum timezone_updates timezone_updates_config = TIMEZONE_UPDATES_AUTO;
46
47 static char *timezone_config = NULL;
48 static char **timeservers_config = NULL;
49
50 static const char *time_updates2string(enum time_updates value)
51 {
52         switch (value) {
53         case TIME_UPDATES_UNKNOWN:
54                 break;
55         case TIME_UPDATES_MANUAL:
56                 return "manual";
57         case TIME_UPDATES_AUTO:
58                 return "auto";
59         }
60
61         return NULL;
62 }
63
64 static enum time_updates string2time_updates(const char *value)
65 {
66         if (g_strcmp0(value, "manual") == 0)
67                 return TIME_UPDATES_MANUAL;
68         else if (g_strcmp0(value, "auto") == 0)
69                 return TIME_UPDATES_AUTO;
70
71         return TIME_UPDATES_UNKNOWN;
72 }
73
74 static const char *timezone_updates2string(enum timezone_updates value)
75 {
76         switch (value) {
77         case TIMEZONE_UPDATES_UNKNOWN:
78                 break;
79         case TIMEZONE_UPDATES_MANUAL:
80                 return "manual";
81         case TIMEZONE_UPDATES_AUTO:
82                 return "auto";
83         }
84
85         return NULL;
86 }
87
88 static enum timezone_updates string2timezone_updates(const char *value)
89 {
90         if (g_strcmp0(value, "manual") == 0)
91                 return TIMEZONE_UPDATES_MANUAL;
92         else if (g_strcmp0(value, "auto") == 0)
93                 return TIMEZONE_UPDATES_AUTO;
94
95         return TIMEZONE_UPDATES_UNKNOWN;
96 }
97
98 static void append_timeservers(DBusMessageIter *iter, void *user_data)
99 {
100         int i;
101
102         if (timeservers_config == NULL)
103                 return;
104
105         for (i = 0; timeservers_config[i] != NULL; i++) {
106                 dbus_message_iter_append_basic(iter,
107                                 DBUS_TYPE_STRING, &timeservers_config[i]);
108         }
109 }
110
111 static DBusMessage *get_properties(DBusConnection *conn,
112                                         DBusMessage *msg, void *data)
113 {
114         DBusMessage *reply;
115         DBusMessageIter array, dict;
116         struct timeval tv;
117         const char *str;
118
119         DBG("conn %p", conn);
120
121         reply = dbus_message_new_method_return(msg);
122         if (reply == NULL)
123                 return NULL;
124
125         dbus_message_iter_init_append(reply, &array);
126
127         connman_dbus_dict_open(&array, &dict);
128
129         if (gettimeofday(&tv, NULL) == 0) {
130                 dbus_uint64_t val = tv.tv_sec;
131
132                 connman_dbus_dict_append_basic(&dict, "Time",
133                                                 DBUS_TYPE_UINT64, &val);
134         }
135
136         str = time_updates2string(time_updates_config);
137         if (str != NULL)
138                 connman_dbus_dict_append_basic(&dict, "TimeUpdates",
139                                                 DBUS_TYPE_STRING, &str);
140
141         if (timezone_config != NULL)
142                 connman_dbus_dict_append_basic(&dict, "Timezone",
143                                         DBUS_TYPE_STRING, &timezone_config);
144
145         str = timezone_updates2string(timezone_updates_config);
146         if (str != NULL)
147                 connman_dbus_dict_append_basic(&dict, "TimezoneUpdates",
148                                                 DBUS_TYPE_STRING, &str);
149
150         connman_dbus_dict_append_array(&dict, "Timeservers",
151                                 DBUS_TYPE_STRING, append_timeservers, NULL);
152
153         connman_dbus_dict_close(&array, &dict);
154
155         return reply;
156 }
157
158 static DBusMessage *set_property(DBusConnection *conn,
159                                         DBusMessage *msg, void *data)
160 {
161         DBusMessageIter iter, value;
162         const char *name;
163         int type;
164
165         DBG("conn %p", conn);
166
167         if (dbus_message_iter_init(msg, &iter) == FALSE)
168                 return __connman_error_invalid_arguments(msg);
169
170         dbus_message_iter_get_basic(&iter, &name);
171         dbus_message_iter_next(&iter);
172         dbus_message_iter_recurse(&iter, &value);
173
174         type = dbus_message_iter_get_arg_type(&value);
175
176         if (g_str_equal(name, "Time") == TRUE) {
177                 struct timeval tv;
178                 dbus_uint64_t newval;
179
180                 if (type != DBUS_TYPE_UINT64)
181                         return __connman_error_invalid_arguments(msg);
182
183                 if (time_updates_config != TIME_UPDATES_MANUAL)
184                         return __connman_error_permission_denied(msg);
185
186                 dbus_message_iter_get_basic(&value, &newval);
187
188                 tv.tv_sec = newval;
189                 tv.tv_usec = 0;
190
191                 if (settimeofday(&tv, NULL) < 0)
192                         return __connman_error_invalid_arguments(msg);
193
194                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
195                                 CONNMAN_CLOCK_INTERFACE, "Time",
196                                 DBUS_TYPE_UINT64, &newval);
197         } else if (g_str_equal(name, "TimeUpdates") == TRUE) {
198                 const char *strval;
199                 enum time_updates newval;
200
201                 if (type != DBUS_TYPE_STRING)
202                         return __connman_error_invalid_arguments(msg);
203
204                 dbus_message_iter_get_basic(&value, &strval);
205                 newval = string2time_updates(strval);
206
207                 if (newval == TIME_UPDATES_UNKNOWN)
208                         return __connman_error_invalid_arguments(msg);
209
210                 if (newval == time_updates_config)
211                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
212
213                 time_updates_config = newval;
214
215                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
216                                 CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
217                                 DBUS_TYPE_STRING, &strval);
218         } else if (g_str_equal(name, "Timezone") == TRUE) {
219                 const char *strval;
220
221                 if (type != DBUS_TYPE_STRING)
222                         return __connman_error_invalid_arguments(msg);
223
224                 if (timezone_updates_config != TIMEZONE_UPDATES_MANUAL)
225                         return __connman_error_permission_denied(msg);
226
227                 dbus_message_iter_get_basic(&value, &strval);
228
229                 if (__connman_timezone_change(strval) < 0)
230                         return __connman_error_invalid_arguments(msg);
231         } else if (g_str_equal(name, "TimezoneUpdates") == TRUE) {
232                 const char *strval;
233                 enum timezone_updates newval;
234
235                 if (type != DBUS_TYPE_STRING)
236                         return __connman_error_invalid_arguments(msg);
237
238                 dbus_message_iter_get_basic(&value, &strval);
239                 newval = string2timezone_updates(strval);
240
241                 if (newval == TIMEZONE_UPDATES_UNKNOWN)
242                         return __connman_error_invalid_arguments(msg);
243
244                 if (newval == timezone_updates_config)
245                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
246
247                 timezone_updates_config = newval;
248
249                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
250                                 CONNMAN_CLOCK_INTERFACE, "TimezoneUpdates",
251                                 DBUS_TYPE_STRING, &strval);
252         } else if (g_str_equal(name, "Timeservers") == TRUE) {
253                 DBusMessageIter entry;
254                 GString *str;
255
256                 if (type != DBUS_TYPE_ARRAY)
257                         return __connman_error_invalid_arguments(msg);
258
259                 str = g_string_new(NULL);
260                 if (str == NULL)
261                         return __connman_error_invalid_arguments(msg);
262
263                 dbus_message_iter_recurse(&value, &entry);
264
265                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
266                         const char *val;
267
268                         dbus_message_iter_get_basic(&entry, &val);
269                         dbus_message_iter_next(&entry);
270
271                         if (str->len > 0)
272                                 g_string_append_printf(str, " %s", val);
273                         else
274                                 g_string_append(str, val);
275                 }
276
277                 g_strfreev(timeservers_config);
278
279                 if (str->len > 0)
280                         timeservers_config = g_strsplit_set(str->str, " ", 0);
281                 else
282                         timeservers_config = NULL;
283
284                 g_string_free(str, TRUE);
285
286                 connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
287                                 CONNMAN_CLOCK_INTERFACE, "Timeservers",
288                                 DBUS_TYPE_STRING, append_timeservers, NULL);
289         } else
290                 return __connman_error_invalid_property(msg);
291
292         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
293 }
294
295 static GDBusMethodTable clock_methods[] = {
296         { "GetProperties", "",   "a{sv}", get_properties },
297         { "SetProperty",   "sv", "",      set_property   },
298         { },
299 };
300
301 static GDBusSignalTable clock_signals[] = {
302         { "PropertyChanged", "sv" },
303         { },
304 };
305
306 static DBusConnection *connection = NULL;
307
308 void __connman_clock_update_timezone(void)
309 {
310         DBG("");
311
312         g_free(timezone_config);
313         timezone_config = __connman_timezone_lookup();
314
315         if (timezone_config == NULL)
316                 return;
317
318         connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
319                                 CONNMAN_CLOCK_INTERFACE, "Timezone",
320                                 DBUS_TYPE_STRING, &timezone_config);
321 }
322
323 int __connman_clock_init(void)
324 {
325         DBG("");
326
327         connection = connman_dbus_get_connection();
328         if (connection == NULL)
329                 return -1;
330
331         __connman_timezone_init();
332
333         timezone_config = __connman_timezone_lookup();
334
335         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
336                                                 CONNMAN_CLOCK_INTERFACE,
337                                                 clock_methods, clock_signals,
338                                                 NULL, NULL, NULL);
339
340         return 0;
341 }
342
343 void __connman_clock_cleanup(void)
344 {
345         DBG("");
346
347         if (connection == NULL)
348                 return;
349
350         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
351                                                 CONNMAN_CLOCK_INTERFACE);
352
353         dbus_connection_unref(connection);
354
355         __connman_timezone_cleanup();
356
357         g_free(timezone_config);
358         g_strfreev(timeservers_config);
359 }