gdhcp: Add RFC 1533- and 2132-compliant client-id option
[framework/connectivity/connman.git] / src / clock.c
index 2f0a025..0d7f870 100644 (file)
 #include <config.h>
 #endif
 
+#include <sys/time.h>
+
 #include <gdbus.h>
 
 #include "connman.h"
 
-static char **timeservers_config = NULL;
+enum time_updates {
+       TIME_UPDATES_UNKNOWN = 0,
+       TIME_UPDATES_MANUAL  = 1,
+       TIME_UPDATES_AUTO    = 2,
+};
+
+enum timezone_updates {
+       TIMEZONE_UPDATES_UNKNOWN = 0,
+       TIMEZONE_UPDATES_MANUAL  = 1,
+       TIMEZONE_UPDATES_AUTO    = 2,
+};
+
+static enum time_updates time_updates_config = TIME_UPDATES_AUTO;
+static enum timezone_updates timezone_updates_config = TIMEZONE_UPDATES_AUTO;
+
+static char *timezone_config = NULL;
+
+static const char *time_updates2string(enum time_updates value)
+{
+       switch (value) {
+       case TIME_UPDATES_UNKNOWN:
+               break;
+       case TIME_UPDATES_MANUAL:
+               return "manual";
+       case TIME_UPDATES_AUTO:
+               return "auto";
+       }
+
+       return NULL;
+}
+
+static enum time_updates string2time_updates(const char *value)
+{
+       if (g_strcmp0(value, "manual") == 0)
+               return TIME_UPDATES_MANUAL;
+       else if (g_strcmp0(value, "auto") == 0)
+               return TIME_UPDATES_AUTO;
+
+       return TIME_UPDATES_UNKNOWN;
+}
+
+static const char *timezone_updates2string(enum timezone_updates value)
+{
+       switch (value) {
+       case TIMEZONE_UPDATES_UNKNOWN:
+               break;
+       case TIMEZONE_UPDATES_MANUAL:
+               return "manual";
+       case TIMEZONE_UPDATES_AUTO:
+               return "auto";
+       }
+
+       return NULL;
+}
+
+static enum timezone_updates string2timezone_updates(const char *value)
+{
+       if (g_strcmp0(value, "manual") == 0)
+               return TIMEZONE_UPDATES_MANUAL;
+       else if (g_strcmp0(value, "auto") == 0)
+               return TIMEZONE_UPDATES_AUTO;
+
+        return TIMEZONE_UPDATES_UNKNOWN;
+}
 
 static void append_timeservers(DBusMessageIter *iter, void *user_data)
 {
        int i;
+       char **timeservers = __connman_timeserver_system_get();
 
-       if (timeservers_config == NULL)
+       if (timeservers == NULL)
                return;
 
-       for (i = 0; timeservers_config[i] != NULL; i++) {
+       for (i = 0; timeservers[i] != NULL; i++) {
                dbus_message_iter_append_basic(iter,
-                               DBUS_TYPE_STRING, &timeservers_config[i]);
+                               DBUS_TYPE_STRING, &timeservers[i]);
        }
+
+       g_strfreev(timeservers);
 }
 
 static DBusMessage *get_properties(DBusConnection *conn,
@@ -47,6 +115,8 @@ static DBusMessage *get_properties(DBusConnection *conn,
 {
        DBusMessage *reply;
        DBusMessageIter array, dict;
+       struct timeval tv;
+       const char *str;
 
        DBG("conn %p", conn);
 
@@ -58,6 +128,27 @@ static DBusMessage *get_properties(DBusConnection *conn,
 
        connman_dbus_dict_open(&array, &dict);
 
+       if (gettimeofday(&tv, NULL) == 0) {
+               dbus_uint64_t val = tv.tv_sec;
+
+               connman_dbus_dict_append_basic(&dict, "Time",
+                                               DBUS_TYPE_UINT64, &val);
+       }
+
+       str = time_updates2string(time_updates_config);
+       if (str != NULL)
+               connman_dbus_dict_append_basic(&dict, "TimeUpdates",
+                                               DBUS_TYPE_STRING, &str);
+
+       if (timezone_config != NULL)
+               connman_dbus_dict_append_basic(&dict, "Timezone",
+                                       DBUS_TYPE_STRING, &timezone_config);
+
+       str = timezone_updates2string(timezone_updates_config);
+       if (str != NULL)
+               connman_dbus_dict_append_basic(&dict, "TimezoneUpdates",
+                                               DBUS_TYPE_STRING, &str);
+
        connman_dbus_dict_append_array(&dict, "Timeservers",
                                DBUS_TYPE_STRING, append_timeservers, NULL);
 
@@ -84,40 +175,101 @@ static DBusMessage *set_property(DBusConnection *conn,
 
        type = dbus_message_iter_get_arg_type(&value);
 
-       if (g_str_equal(name, "Timeservers") == TRUE) {
-               DBusMessageIter entry;
-               GString *str;
+       if (g_str_equal(name, "Time") == TRUE) {
+               struct timeval tv;
+               dbus_uint64_t newval;
 
-               if (type != DBUS_TYPE_ARRAY)
+               if (type != DBUS_TYPE_UINT64)
+                       return __connman_error_invalid_arguments(msg);
+
+               if (time_updates_config != TIME_UPDATES_MANUAL)
+                       return __connman_error_permission_denied(msg);
+
+               dbus_message_iter_get_basic(&value, &newval);
+
+               tv.tv_sec = newval;
+               tv.tv_usec = 0;
+
+               if (settimeofday(&tv, NULL) < 0)
+                       return __connman_error_invalid_arguments(msg);
+
+               connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "Time",
+                               DBUS_TYPE_UINT64, &newval);
+       } else if (g_str_equal(name, "TimeUpdates") == TRUE) {
+               const char *strval;
+               enum time_updates newval;
+
+               if (type != DBUS_TYPE_STRING)
+                       return __connman_error_invalid_arguments(msg);
+
+               dbus_message_iter_get_basic(&value, &strval);
+               newval = string2time_updates(strval);
+
+               if (newval == TIME_UPDATES_UNKNOWN)
+                       return __connman_error_invalid_arguments(msg);
+
+               if (newval == time_updates_config)
+                       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+               time_updates_config = newval;
+
+               connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
+                               DBUS_TYPE_STRING, &strval);
+       } else if (g_str_equal(name, "Timezone") == TRUE) {
+               const char *strval;
+
+               if (type != DBUS_TYPE_STRING)
                        return __connman_error_invalid_arguments(msg);
 
-               str = g_string_new(NULL);
-               if (str == NULL)
+               if (timezone_updates_config != TIMEZONE_UPDATES_MANUAL)
+                       return __connman_error_permission_denied(msg);
+
+               dbus_message_iter_get_basic(&value, &strval);
+
+               if (__connman_timezone_change(strval) < 0)
+                        return __connman_error_invalid_arguments(msg);
+       } else if (g_str_equal(name, "TimezoneUpdates") == TRUE) {
+               const char *strval;
+               enum timezone_updates newval;
+
+               if (type != DBUS_TYPE_STRING)
+                       return __connman_error_invalid_arguments(msg);
+
+               dbus_message_iter_get_basic(&value, &strval);
+               newval = string2timezone_updates(strval);
+
+               if (newval == TIMEZONE_UPDATES_UNKNOWN)
+                       return __connman_error_invalid_arguments(msg);
+
+               if (newval == timezone_updates_config)
+                       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+               timezone_updates_config = newval;
+
+               connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "TimezoneUpdates",
+                               DBUS_TYPE_STRING, &strval);
+       } else if (g_str_equal(name, "Timeservers") == TRUE) {
+               DBusMessageIter entry;
+
+               if (type != DBUS_TYPE_ARRAY)
                        return __connman_error_invalid_arguments(msg);
 
                dbus_message_iter_recurse(&value, &entry);
 
+               if (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_INVALID)
+                       __connman_timeserver_system_append(NULL);
+
                while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
                        const char *val;
 
                        dbus_message_iter_get_basic(&entry, &val);
+                       __connman_timeserver_system_append(val);
                        dbus_message_iter_next(&entry);
-
-                       if (str->len > 0)
-                               g_string_append_printf(str, " %s", val);
-                       else
-                               g_string_append(str, val);
                }
 
-               g_strfreev(timeservers_config);
-
-               if (str->len > 0)
-                       timeservers_config = g_strsplit_set(str->str, " ", 0);
-               else
-                       timeservers_config = NULL;
-
-               g_string_free(str, TRUE);
-
                connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
                                CONNMAN_CLOCK_INTERFACE, "Timeservers",
                                DBUS_TYPE_STRING, append_timeservers, NULL);
@@ -140,6 +292,21 @@ static GDBusSignalTable clock_signals[] = {
 
 static DBusConnection *connection = NULL;
 
+void __connman_clock_update_timezone(void)
+{
+       DBG("");
+
+       g_free(timezone_config);
+       timezone_config = __connman_timezone_lookup();
+
+       if (timezone_config == NULL)
+               return;
+
+       connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "Timezone",
+                               DBUS_TYPE_STRING, &timezone_config);
+}
+
 int __connman_clock_init(void)
 {
        DBG("");
@@ -148,6 +315,10 @@ int __connman_clock_init(void)
        if (connection == NULL)
                return -1;
 
+       __connman_timezone_init();
+
+       timezone_config = __connman_timezone_lookup();
+
        g_dbus_register_interface(connection, CONNMAN_MANAGER_PATH,
                                                CONNMAN_CLOCK_INTERFACE,
                                                clock_methods, clock_signals,
@@ -168,5 +339,7 @@ void __connman_clock_cleanup(void)
 
        dbus_connection_unref(connection);
 
-       g_strfreev(timeservers_config);
+       __connman_timezone_cleanup();
+
+       g_free(timezone_config);
 }