clock: Add support for time and timezone update 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 <gdbus.h>
27
28 #include "connman.h"
29
30 enum time_updates {
31         TIME_UPDATES_UNKNOWN = 0,
32         TIME_UPDATES_MANUAL  = 1,
33         TIME_UPDATES_AUTO    = 2,
34 };
35
36 enum timezone_updates {
37         TIMEZONE_UPDATES_UNKNOWN = 0,
38         TIMEZONE_UPDATES_MANUAL  = 1,
39         TIMEZONE_UPDATES_AUTO    = 2,
40 };
41
42 static enum time_updates time_updates_config = TIME_UPDATES_AUTO;
43 static enum timezone_updates timezone_updates_config = TIMEZONE_UPDATES_AUTO;
44
45 static char **timeservers_config = NULL;
46
47 static const char *time_updates2string(enum time_updates value)
48 {
49         switch (value) {
50         case TIME_UPDATES_UNKNOWN:
51                 break;
52         case TIME_UPDATES_MANUAL:
53                 return "manual";
54         case TIME_UPDATES_AUTO:
55                 return "auto";
56         }
57
58         return NULL;
59 }
60
61 static enum time_updates string2time_updates(const char *value)
62 {
63         if (g_strcmp0(value, "manual") == 0)
64                 return TIME_UPDATES_MANUAL;
65         else if (g_strcmp0(value, "auto") == 0)
66                 return TIME_UPDATES_AUTO;
67
68         return TIME_UPDATES_UNKNOWN;
69 }
70
71 static const char *timezone_updates2string(enum timezone_updates value)
72 {
73         switch (value) {
74         case TIMEZONE_UPDATES_UNKNOWN:
75                 break;
76         case TIMEZONE_UPDATES_MANUAL:
77                 return "manual";
78         case TIMEZONE_UPDATES_AUTO:
79                 return "auto";
80         }
81
82         return NULL;
83 }
84
85 static enum timezone_updates string2timezone_updates(const char *value)
86 {
87         if (g_strcmp0(value, "manual") == 0)
88                 return TIMEZONE_UPDATES_MANUAL;
89         else if (g_strcmp0(value, "auto") == 0)
90                 return TIMEZONE_UPDATES_AUTO;
91
92         return TIMEZONE_UPDATES_UNKNOWN;
93 }
94
95 static void append_timeservers(DBusMessageIter *iter, void *user_data)
96 {
97         int i;
98
99         if (timeservers_config == NULL)
100                 return;
101
102         for (i = 0; timeservers_config[i] != NULL; i++) {
103                 dbus_message_iter_append_basic(iter,
104                                 DBUS_TYPE_STRING, &timeservers_config[i]);
105         }
106 }
107
108 static DBusMessage *get_properties(DBusConnection *conn,
109                                         DBusMessage *msg, void *data)
110 {
111         DBusMessage *reply;
112         DBusMessageIter array, dict;
113         const char *str;
114
115         DBG("conn %p", conn);
116
117         reply = dbus_message_new_method_return(msg);
118         if (reply == NULL)
119                 return NULL;
120
121         dbus_message_iter_init_append(reply, &array);
122
123         connman_dbus_dict_open(&array, &dict);
124
125         str = time_updates2string(time_updates_config);
126         if (str != NULL)
127                 connman_dbus_dict_append_basic(&dict, "TimeUpdates",
128                                                 DBUS_TYPE_STRING, &str);
129
130         str = timezone_updates2string(timezone_updates_config);
131         if (str != NULL)
132                 connman_dbus_dict_append_basic(&dict, "TimezoneUpdates",
133                                                 DBUS_TYPE_STRING, &str);
134
135         connman_dbus_dict_append_array(&dict, "Timeservers",
136                                 DBUS_TYPE_STRING, append_timeservers, NULL);
137
138         connman_dbus_dict_close(&array, &dict);
139
140         return reply;
141 }
142
143 static DBusMessage *set_property(DBusConnection *conn,
144                                         DBusMessage *msg, void *data)
145 {
146         DBusMessageIter iter, value;
147         const char *name;
148         int type;
149
150         DBG("conn %p", conn);
151
152         if (dbus_message_iter_init(msg, &iter) == FALSE)
153                 return __connman_error_invalid_arguments(msg);
154
155         dbus_message_iter_get_basic(&iter, &name);
156         dbus_message_iter_next(&iter);
157         dbus_message_iter_recurse(&iter, &value);
158
159         type = dbus_message_iter_get_arg_type(&value);
160
161         if (g_str_equal(name, "TimeUpdates") == TRUE) {
162                 const char *strval;
163                 enum time_updates newval;
164
165                 if (type != DBUS_TYPE_STRING)
166                         return __connman_error_invalid_arguments(msg);
167
168                 dbus_message_iter_get_basic(&value, &strval);
169                 newval = string2time_updates(strval);
170
171                 if (newval == TIME_UPDATES_UNKNOWN)
172                         return __connman_error_invalid_arguments(msg);
173
174                 if (newval == time_updates_config)
175                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
176
177                 time_updates_config = newval;
178
179                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
180                                 CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
181                                 DBUS_TYPE_STRING, &strval);
182         } else if (g_str_equal(name, "TimezoneUpdates") == TRUE) {
183                 const char *strval;
184                 enum timezone_updates newval;
185
186                 if (type != DBUS_TYPE_STRING)
187                         return __connman_error_invalid_arguments(msg);
188
189                 dbus_message_iter_get_basic(&value, &strval);
190                 newval = string2timezone_updates(strval);
191
192                 if (newval == TIMEZONE_UPDATES_UNKNOWN)
193                         return __connman_error_invalid_arguments(msg);
194
195                 if (newval == timezone_updates_config)
196                         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
197
198                 timezone_updates_config = newval;
199
200                 connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
201                                 CONNMAN_CLOCK_INTERFACE, "TimezoneUpdates",
202                                 DBUS_TYPE_STRING, &strval);
203         } else if (g_str_equal(name, "Timeservers") == TRUE) {
204                 DBusMessageIter entry;
205                 GString *str;
206
207                 if (type != DBUS_TYPE_ARRAY)
208                         return __connman_error_invalid_arguments(msg);
209
210                 str = g_string_new(NULL);
211                 if (str == NULL)
212                         return __connman_error_invalid_arguments(msg);
213
214                 dbus_message_iter_recurse(&value, &entry);
215
216                 while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
217                         const char *val;
218
219                         dbus_message_iter_get_basic(&entry, &val);
220                         dbus_message_iter_next(&entry);
221
222                         if (str->len > 0)
223                                 g_string_append_printf(str, " %s", val);
224                         else
225                                 g_string_append(str, val);
226                 }
227
228                 g_strfreev(timeservers_config);
229
230                 if (str->len > 0)
231                         timeservers_config = g_strsplit_set(str->str, " ", 0);
232                 else
233                         timeservers_config = NULL;
234
235                 g_string_free(str, TRUE);
236
237                 connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
238                                 CONNMAN_CLOCK_INTERFACE, "Timeservers",
239                                 DBUS_TYPE_STRING, append_timeservers, NULL);
240         } else
241                 return __connman_error_invalid_property(msg);
242
243         return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
244 }
245
246 static GDBusMethodTable clock_methods[] = {
247         { "GetProperties", "",   "a{sv}", get_properties },
248         { "SetProperty",   "sv", "",      set_property   },
249         { },
250 };
251
252 static GDBusSignalTable clock_signals[] = {
253         { "PropertyChanged", "sv" },
254         { },
255 };
256
257 static DBusConnection *connection = NULL;
258
259 int __connman_clock_init(void)
260 {
261         DBG("");
262
263         connection = connman_dbus_get_connection();
264         if (connection == NULL)
265                 return -1;
266
267         g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
268                                                 CONNMAN_CLOCK_INTERFACE,
269                                                 clock_methods, clock_signals,
270                                                 NULL, NULL, NULL);
271
272         return 0;
273 }
274
275 void __connman_clock_cleanup(void)
276 {
277         DBG("");
278
279         if (connection == NULL)
280                 return;
281
282         g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
283                                                 CONNMAN_CLOCK_INTERFACE);
284
285         dbus_connection_unref(connection);
286
287         g_strfreev(timeservers_config);
288 }