Added a dbus property 'TimeUpdated'
[platform/upstream/connman.git] / src / clock.c
old mode 100644 (file)
new mode 100755 (executable)
index 3a59f31..40729b2
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2013  Intel Corporation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
 #include <config.h>
 #endif
 
+#include <sys/time.h>
+
+#include <gdbus.h>
+
 #include "connman.h"
 
+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;
+#if defined TIZEN_EXT
+static bool time_updated = false;
+#endif
+
+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 clock_properties_load(void)
+{
+       GKeyFile *keyfile;
+       char *str;
+       enum time_updates time_value;
+       enum timezone_updates timezone_value;
+
+       keyfile = __connman_storage_load_global();
+       if (!keyfile)
+               return;
+
+       str = g_key_file_get_string(keyfile, "global", "TimeUpdates", NULL);
+
+       time_value = string2time_updates(str);
+       if (time_value != TIME_UPDATES_UNKNOWN)
+               time_updates_config = time_value;
+
+       g_free(str);
+
+       str = g_key_file_get_string(keyfile, "global", "TimezoneUpdates",
+                       NULL);
+
+       timezone_value = string2timezone_updates(str);
+       if (timezone_value != TIMEZONE_UPDATES_UNKNOWN)
+               timezone_updates_config = timezone_value;
+
+       g_free(str);
+
+       g_key_file_free(keyfile);
+}
+
+static void clock_properties_save(void)
+{
+       GKeyFile *keyfile;
+       const char *str;
+
+       keyfile = __connman_storage_load_global();
+       if (!keyfile)
+               keyfile = g_key_file_new();
+
+       str = time_updates2string(time_updates_config);
+       if (str)
+               g_key_file_set_string(keyfile, "global", "TimeUpdates", str);
+       else
+               g_key_file_remove_key(keyfile, "global", "TimeUpdates", NULL);
+
+       str = timezone_updates2string(timezone_updates_config);
+       if (str)
+               g_key_file_set_string(keyfile, "global", "TimezoneUpdates",
+                               str);
+       else
+               g_key_file_remove_key(keyfile, "global", "TimezoneUpdates",
+                               NULL);
+
+       __connman_storage_save_global(keyfile);
+
+       g_key_file_free(keyfile);
+}
+
+enum time_updates __connman_clock_timeupdates(void)
+{
+       return time_updates_config;
+}
+
+static void append_timeservers(DBusMessageIter *iter, void *user_data)
+{
+       int i;
+       char **timeservers = __connman_timeserver_system_get();
+
+       if (!timeservers)
+               return;
+
+       for (i = 0; timeservers[i]; i++) {
+               dbus_message_iter_append_basic(iter,
+                               DBUS_TYPE_STRING, &timeservers[i]);
+       }
+
+       g_strfreev(timeservers);
+}
+
+static DBusMessage *get_properties(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       DBusMessage *reply;
+       DBusMessageIter array, dict;
+       struct timeval tv;
+       const char *str;
+#if defined TIZEN_EXT
+       dbus_bool_t val = time_updated;
+#endif
+
+       DBG("conn %p", conn);
+
+       reply = dbus_message_new_method_return(msg);
+       if (!reply)
+               return NULL;
+
+       dbus_message_iter_init_append(reply, &array);
+
+       connman_dbus_dict_open(&array, &dict);
+
+#if defined TIZEN_EXT
+       connman_dbus_dict_append_basic(&dict, "TimeUpdated",
+                                               DBUS_TYPE_BOOLEAN,
+                                               &val);
+#endif
+
+       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)
+               connman_dbus_dict_append_basic(&dict, "TimeUpdates",
+                                               DBUS_TYPE_STRING, &str);
+
+       if (timezone_config)
+               connman_dbus_dict_append_basic(&dict, "Timezone",
+                                       DBUS_TYPE_STRING, &timezone_config);
+
+       str = timezone_updates2string(timezone_updates_config);
+       if (str)
+               connman_dbus_dict_append_basic(&dict, "TimezoneUpdates",
+                                               DBUS_TYPE_STRING, &str);
+
+       connman_dbus_dict_append_array(&dict, "Timeservers",
+                               DBUS_TYPE_STRING, append_timeservers, NULL);
+
+       connman_dbus_dict_close(&array, &dict);
+
+       return reply;
+}
+
+static DBusMessage *set_property(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       DBusMessageIter iter, value;
+       const char *name;
+       int type;
+
+       DBG("conn %p", conn);
+
+       if (!dbus_message_iter_init(msg, &iter))
+               return __connman_error_invalid_arguments(msg);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return __connman_error_invalid_arguments(msg);
+
+       dbus_message_iter_get_basic(&iter, &name);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+               return __connman_error_invalid_arguments(msg);
+
+       dbus_message_iter_recurse(&iter, &value);
+
+       type = dbus_message_iter_get_arg_type(&value);
+
+       if (g_str_equal(name, "Time")) {
+#if defined TIZEN_EXT
+               /* Tizen updates time (ntp) by system service */
+
+               return __connman_error_permission_denied(msg);
+#else
+               struct timeval tv;
+               dbus_uint64_t newval;
+
+               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);
+#endif
+       } else if (g_str_equal(name, "TimeUpdates")) {
+               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;
+
+               clock_properties_save();
+               connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "TimeUpdates",
+                               DBUS_TYPE_STRING, &strval);
+       } else if (g_str_equal(name, "Timezone")) {
+               const char *strval;
+
+               if (type != DBUS_TYPE_STRING)
+                       return __connman_error_invalid_arguments(msg);
+
+               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")) {
+               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;
+
+               clock_properties_save();
+               connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "TimezoneUpdates",
+                               DBUS_TYPE_STRING, &strval);
+       } else if (g_str_equal(name, "Timeservers")) {
+               DBusMessageIter entry;
+               char **str = NULL;
+               GSList *list = NULL;
+               int count = 0;
+
+               if (type != DBUS_TYPE_ARRAY)
+                       return __connman_error_invalid_arguments(msg);
+
+               dbus_message_iter_recurse(&value, &entry);
+
+               while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+                       const char *val;
+                       GSList *new_head;
+
+                       dbus_message_iter_get_basic(&entry, &val);
+
+                       new_head = __connman_timeserver_add_list(list, val);
+                       if (list != new_head) {
+                               count++;
+                               list = new_head;
+                       }
+
+                       dbus_message_iter_next(&entry);
+               }
+
+               if (list) {
+                       str = g_new0(char *, count+1);
+
+                       while (list) {
+                               count--;
+                               str[count] = list->data;
+                               list = g_slist_delete_link(list, list);
+                       };
+               }
+
+               __connman_timeserver_system_set(str);
+
+               if (str)
+                       g_strfreev(str);
+
+               connman_dbus_property_changed_array(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "Timeservers",
+                               DBUS_TYPE_STRING, append_timeservers, NULL);
+       } else
+               return __connman_error_invalid_property(msg);
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable clock_methods[] = {
+       { GDBUS_METHOD("GetProperties",
+                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+                       get_properties) },
+       { GDBUS_METHOD("SetProperty",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL,
+                       set_property)   },
+       { },
+};
+
+static const GDBusSignalTable clock_signals[] = {
+       { GDBUS_SIGNAL("PropertyChanged",
+                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+       { },
+};
+
+static DBusConnection *connection = NULL;
+
+#if defined TIZEN_EXT
+void __connman_clock_set_time_updated(bool updated)
+{
+       time_updated = updated;
+}
+#endif
+
+void __connman_clock_update_timezone(void)
+{
+       DBG("");
+
+       g_free(timezone_config);
+       timezone_config = __connman_timezone_lookup();
+
+       if (!timezone_config)
+               return;
+
+       connman_dbus_property_changed_basic(CONNMAN_MANAGER_PATH,
+                               CONNMAN_CLOCK_INTERFACE, "Timezone",
+                               DBUS_TYPE_STRING, &timezone_config);
+}
+
 int __connman_clock_init(void)
 {
        DBG("");
 
+       connection = connman_dbus_get_connection();
+       if (!connection)
+               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,
+                                               NULL, NULL, NULL);
+
+       clock_properties_load();
        return 0;
 }
 
 void __connman_clock_cleanup(void)
 {
        DBG("");
+
+       if (!connection)
+               return;
+
+       g_dbus_unregister_interface(connection, CONNMAN_MANAGER_PATH,
+                                               CONNMAN_CLOCK_INTERFACE);
+
+       dbus_connection_unref(connection);
+
+       __connman_timezone_cleanup();
+
+       g_free(timezone_config);
 }