clock: Add support for retrieving time and timezone properties
[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, "TimeUpdates") == TRUE) {
177                 const char *strval;
178                 enum time_updates newval;
179
180                 if (type != DBUS_TYPE_STRING)
181                         return __connman_error_invalid_arguments(msg);
182
183                 dbus_message_iter_get_basic(&value, &strval);
184                 newval = string2time_updates(strval);
185
186                 if (newval == TIME_UPDATES_UNKNOWN)
187                         return __connman_error_invalid_arguments(msg);
188
189                 if (newval == time_updates_config)
190                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
191
192                 time_updates_config = newval;
193
194                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
195                                 CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
196                                 DBUS_TYPE_STRING, &strval);
197         } else if (g_str_equal(name, "TimezoneUpdates") == TRUE) {
198                 const char *strval;
199                 enum timezone_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 = string2timezone_updates(strval);
206
207                 if (newval == TIMEZONE_UPDATES_UNKNOWN)
208                         return __connman_error_invalid_arguments(msg);
209
210                 if (newval == timezone_updates_config)
211                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
212
213                 timezone_updates_config = newval;
214
215                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
216                                 CONNMAN_CLOCK_INTERFACE, "TimezoneUpdates",
217                                 DBUS_TYPE_STRING, &strval);
218         } else if (g_str_equal(name, "Timeservers") == TRUE) {
219                 DBusMessageIter entry;
220                 GString *str;
221
222                 if (type != DBUS_TYPE_ARRAY)
223                         return __connman_error_invalid_arguments(msg);
224
225                 str = g_string_new(NULL);
226                 if (str == NULL)
227                         return __connman_error_invalid_arguments(msg);
228
229                 dbus_message_iter_recurse(&value, &entry);
230
231                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
232                         const char *val;
233
234                         dbus_message_iter_get_basic(&entry, &val);
235                         dbus_message_iter_next(&entry);
236
237                         if (str->len > 0)
238                                 g_string_append_printf(str, " %s", val);
239                         else
240                                 g_string_append(str, val);
241                 }
242
243                 g_strfreev(timeservers_config);
244
245                 if (str->len > 0)
246                         timeservers_config = g_strsplit_set(str->str, " ", 0);
247                 else
248                         timeservers_config = NULL;
249
250                 g_string_free(str, TRUE);
251
252                 connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
253                                 CONNMAN_CLOCK_INTERFACE, "Timeservers",
254                                 DBUS_TYPE_STRING, append_timeservers, NULL);
255         } else
256                 return __connman_error_invalid_property(msg);
257
258         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
259 }
260
261 static GDBusMethodTable clock_methods[] = {
262         { "GetProperties", "",   "a{sv}", get_properties },
263         { "SetProperty",   "sv", "",      set_property   },
264         { },
265 };
266
267 static GDBusSignalTable clock_signals[] = {
268         { "PropertyChanged", "sv" },
269         { },
270 };
271
272 static DBusConnection *connection = NULL;
273
274 int __connman_clock_init(void)
275 {
276         DBG("");
277
278         connection = connman_dbus_get_connection();
279         if (connection == NULL)
280                 return -1;
281
282         timezone_config = __connman_timezone_lookup();
283
284         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
285                                                 CONNMAN_CLOCK_INTERFACE,
286                                                 clock_methods, clock_signals,
287                                                 NULL, NULL, NULL);
288
289         return 0;
290 }
291
292 void __connman_clock_cleanup(void)
293 {
294         DBG("");
295
296         if (connection == NULL)
297                 return;
298
299         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
300                                                 CONNMAN_CLOCK_INTERFACE);
301
302         dbus_connection_unref(connection);
303
304         g_free(timezone_config);
305         g_strfreev(timeservers_config);
306 }