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