--- plugins/nettime.c | 317 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 317 insertions(+), 0 deletions(-) create mode 100644 plugins/nettime.c
diff --git a/plugins/nettime.c b/plugins/nettime.c new file mode 100644 index 0000000..ee24320 --- /dev/null +++ b/plugins/nettime.c @@ -0,0 +1,317 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). + * + * 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 + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdlib.h> +#include <glib.h> + +#define OFONO_API_SUBJECT_TO_CHANGE +#include <ofono/plugin.h> +#include <ofono/log.h> +#include <ofono/nettime.h> +#include <ofono/types.h> +#include <gdbus.h> +#include "ofono.h" + +#include "common.h" + +#define TIMED_PATH "/com/meego/time" +#define TIMED_SERVICE "com.meego.time" + +struct nt_data { + gboolean time_available; + gboolean time_pending; + + time_t nw_time_utc; + time_t received; + + int dst; + int time_zone; + + const char *mcc; + const char *mnc; +}; + +static void nettime_register(struct ofono_nettime_context *); + +static gboolean encode_time_format(struct ofono_network_time *time, + struct tm *tm) +{ + if (time->year < 0) + return FALSE; + + tm->tm_year = time->year - 1900; + tm->tm_mon = time->mon - 1; + tm->tm_mday = time->mday; + tm->tm_hour = time->hour; + tm->tm_min = time->min; + tm->tm_sec = time->sec; + tm->tm_gmtoff = time->utcoff; + tm->tm_isdst = time->dst; + + return TRUE; +} + +static time_t get_monotonic_time() +{ + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec; +} + +static int fill_time_notification(DBusMessage *msg, + struct nt_data *ntd) +{ + DBusMessageIter iter, iter_array; + time_t utc; + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_open_container(&iter, + DBUS_TYPE_ARRAY, + "{sv}", + &iter_array); + + if (ntd->time_pending) { + if (ntd->time_available) { + utc = ntd->nw_time_utc - ntd->received; + + ofono_dbus_dict_append(&iter_array, + "UTC", + DBUS_TYPE_INT64, + &utc); + ofono_dbus_dict_append(&iter_array, + "DST", + DBUS_TYPE_UINT32, + &ntd->dst); + } + + ofono_dbus_dict_append(&iter_array, + "Timezone", + DBUS_TYPE_INT32, + &ntd->time_zone); + } + + ofono_dbus_dict_append(&iter_array, + "MobileCountryCode", + DBUS_TYPE_STRING, + &ntd->mcc); + ofono_dbus_dict_append(&iter_array, + "MobileNetworkCode", + DBUS_TYPE_STRING, + &ntd->mnc); + + dbus_message_iter_close_container(&iter, &iter_array); + return 0; +} + +static DBusMessage *create_time_notification( + struct ofono_nettime_context *context) +{ + DBusMessage *message; + struct nt_data *ntd = context->data; + const char *path = ofono_modem_get_path(context->modem); + + if (path == NULL) { + ofono_error("Fetching path for modem failed"); + return NULL; + } + + message = dbus_message_new_method_call(TIMED_SERVICE, TIMED_PATH, + "org.ofono.NetworkTime", "Notify"); + if (message == NULL) + return NULL; + + dbus_message_set_no_reply(message, TRUE); + fill_time_notification(message, ntd); + + return message; +} + +static void init_time(struct ofono_nettime_context *context) +{ + struct nt_data *nt_data = g_new0(struct nt_data, 1); + + nt_data->time_available = FALSE; + nt_data->time_pending = FALSE; + nt_data->dst = 0; + nt_data->time_zone = 0; + + context->data = nt_data; +} + +static int nettime_probe(struct ofono_nettime_context *context) +{ + DBG("Network Time Probe for modem: %p", context->modem); + + init_time(context); + nettime_register(context); + + return 0; +} + +static void nettime_remove(struct ofono_nettime_context *context) +{ + DBG("Network Time Remove for modem: %p", context->modem); + g_dbus_remove_watch(ofono_dbus_get_connection(), + context->timed_watch); + g_free(context->data); +} + +static void notify(int status, int lac, int ci, int tech, const char *mcc, + const char *mnc, void *data) +{ + struct ofono_nettime_context *context = data; + struct nt_data *ntd = context->data; + DBusMessage *message; + + if (mcc == NULL || mnc == NULL) + return; + + ntd->mcc = mcc; + ntd->mnc = mnc; + + if (context->timed_present == FALSE) { + DBG("Timed not present. Caching time info"); + return; + } + + message = create_time_notification(context); + if (message == NULL) { + ofono_error("Failed to create Notification message"); + return; + } + + g_dbus_send_message(ofono_dbus_get_connection(), message); + ntd->time_pending = FALSE; +} + +static void nr_st_watch_destroy(void *data) +{ + struct ofono_nettime_context *context = data; + DBG(""); + + context->netreg_st_watch = 0; +} + +static void nettime_info_received(struct ofono_nettime_context *context, + struct ofono_network_time *info) +{ + struct tm t; + struct nt_data *ntd = context->data; + const char *mcc, *mnc; + + DBG("Network time notification received, modem: %p", + context->modem); + + if (info == NULL) + return; + + ntd->received = get_monotonic_time(); + ntd->time_pending = TRUE; + + ntd->time_available = encode_time_format(info, &t); + if (ntd->time_available == TRUE) + ntd->nw_time_utc = timegm(&t); + + ntd->dst = info->dst; + ntd->time_zone = info->utcoff; + + context->netreg = __ofono_atom_get_data(__ofono_modem_find_atom( + context->modem, OFONO_ATOM_TYPE_NETREG)); + + mcc = ofono_netreg_get_mcc(context->netreg); + mnc = ofono_netreg_get_mnc(context->netreg); + if ((mcc == NULL) || (mnc == NULL)) { + DBG("Mobile country/network code missing"); + + if (context->netreg_st_watch != 0) + return; + + context->netreg_st_watch = __ofono_netreg_add_status_watch( + context->netreg, notify, + context, nr_st_watch_destroy); + } else { + notify(0, 0, 0, 0, mcc, mnc, context); + } + +} + +static struct ofono_nettime_driver nettime_driver = { + .name = "Network Time", + .probe = nettime_probe, + .remove = nettime_remove, + .info_received = nettime_info_received, +}; + +static int nettime_init(void) +{ + return ofono_nettime_driver_register(&nettime_driver); +} + +static void nettime_exit(void) +{ + ofono_nettime_driver_unregister(&nettime_driver); +} + +static void timed_connect(DBusConnection *connection, void *user_data) +{ + struct ofono_nettime_context *context = user_data; + const char *mcc, *mnc; + + DBG(""); + + context->timed_present = TRUE; + mcc = ofono_netreg_get_mcc(context->netreg); + mnc = ofono_netreg_get_mnc(context->netreg); + + notify(0, 0, 0, 0, mcc, mnc, context); +} + +static void timed_disconnect(DBusConnection *connection, void *user_data) +{ + struct ofono_nettime_context *context = user_data; + + DBG(""); + + context->timed_present = FALSE; +} + +static void nettime_register(struct ofono_nettime_context *context) +{ + DBusConnection *conn; + + DBG("Registering Network time for modem %s" , + ofono_modem_get_path(context->modem)); + + conn = ofono_dbus_get_connection(); + + context->timed_watch = g_dbus_add_service_watch(conn, TIMED_SERVICE, + timed_connect, timed_disconnect, + context, NULL); +} + +OFONO_PLUGIN_DEFINE(nettime, "Network Time Plugin", + VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, + nettime_init, nettime_exit) + -- 1.7.1 _______________________________________________ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono