--- plugins/meego-nettime.c | 321 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 321 insertions(+), 0 deletions(-) create mode 100644 plugins/meego-nettime.c diff --git a/plugins/meego-nettime.c b/plugins/meego-nettime.c new file mode 100644 index 0000000..442925c --- /dev/null +++ b/plugins/meego-nettime.c @@ -0,0 +1,321 @@ +/* + * + * 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 +#endif + +#include +#include + +#define OFONO_API_SUBJECT_TO_CHANGE +#include +#include +#include +#include +#include +#include +#include "ofono.h" +#include "common.h" + +#define TIMED_PATH "/com/meego/timed" +#define TIMED_SERVICE "com.meego.timed" + +struct nt_data { + gboolean time_available; + gboolean time_pending; + time_t nw_time_utc; + time_t received; + int dst; + int time_zone; + char mcc[OFONO_MAX_MCC_LENGTH + 1]; + char mnc[OFONO_MAX_MNC_LENGTH + 1]; + unsigned int timed_watch; + gboolean timed_present; + struct ofono_netreg *netreg; + unsigned int netreg_status_watch; + unsigned int netreg_watch; +}; + +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; + + 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; + int64_t utc; + + const char *mcc = ntd->mcc; + const char *mnc = ntd->mnc; + + 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_INT32, + &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, + &mcc); + ofono_dbus_dict_append(&iter_array, + "MobileNetworkCode", + DBUS_TYPE_STRING, + &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, + "com.meego.NetworkTime", "Notify"); + + if (message == NULL) + return NULL; + + dbus_message_set_no_reply(message, TRUE); + fill_time_notification(message, ntd); + + return message; +} + +static void nettime_remove(struct ofono_nettime_context *context) +{ + struct nt_data *ntd = context->data; + + DBG("Network Time Remove for modem: %p", context->modem); + + if (ntd->timed_watch > 0) + g_dbus_remove_watch(ofono_dbus_get_connection(), + ntd->timed_watch); + + if (ntd->netreg_status_watch > 0 && ntd->netreg != NULL) { + __ofono_netreg_remove_status_watch(ntd->netreg, + ntd->netreg_status_watch); + } + + __ofono_modem_remove_atom_watch(context->modem, + ntd->netreg_watch); + g_free(ntd); +} + +static void notify(void *data) +{ + struct ofono_nettime_context *context = data; + struct nt_data *ntd = context->data; + DBusMessage *message; + const char *mcc, *mnc; + + mcc = ofono_netreg_get_mcc(ntd->netreg); + mnc = ofono_netreg_get_mnc(ntd->netreg); + + if (ntd->timed_present == FALSE || + mcc == NULL || + mnc == NULL || + (strcmp(ntd->mnc, mnc) == 0 && + strcmp(ntd->mcc, mcc) == 0 && + ntd->time_pending == FALSE)) + return; + + strcpy(ntd->mnc, mnc); + strcpy(ntd->mcc, mcc); + + 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 notify_cb(int status, int lac, int ci, int tech, + const char *mcc, const char *mnc, void *data) +{ + if (mcc != NULL && mnc != NULL) + notify(data); +} + + +static void nettime_info_received(struct ofono_nettime_context *context, + struct ofono_network_time *info) +{ + struct tm t; + struct nt_data *ntd = context->data; + + 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; + + notify(context); + +} + +static void timed_connect(DBusConnection *connection, void *user_data) +{ + struct ofono_nettime_context *context = user_data; + struct nt_data *ntd = context->data; + + ntd->timed_present = TRUE; + + notify(context); +} + +static void timed_disconnect(DBusConnection *connection, void *user_data) +{ + struct ofono_nettime_context *context = user_data; + struct nt_data *ntd = context->data; + + ntd->timed_present = FALSE; +} + +static void netreg_watch_cb(struct ofono_atom *atom, + enum ofono_atom_watch_condition cond, + void *data) +{ + struct ofono_nettime_context *context = data; + struct nt_data *ntd = context->data; + + if (cond == OFONO_ATOM_WATCH_CONDITION_REGISTERED) { + ntd->netreg = __ofono_atom_get_data(atom); + ntd->netreg_status_watch = __ofono_netreg_add_status_watch( + ntd->netreg, notify_cb, + context, NULL); + } else { + ntd->netreg_status_watch = 0; + ntd->netreg = NULL; + } +} + +static int nettime_probe(struct ofono_nettime_context *context) +{ + + DBusConnection *conn = ofono_dbus_get_connection(); + struct nt_data *ntd = g_new0(struct nt_data, 1); + + DBG("Network Time Probe for modem: %p", context->modem); + + context->data = ntd; + + if (ntd->timed_watch == 0) + ntd->timed_watch = g_dbus_add_service_watch(conn, TIMED_SERVICE, + timed_connect, timed_disconnect, + context, NULL); + + if (ntd->netreg_watch == 0) + ntd->netreg_watch = __ofono_modem_add_atom_watch( + context->modem, + OFONO_ATOM_TYPE_NETREG, + netreg_watch_cb, + context, NULL); + + return 0; +} + +static struct ofono_nettime_driver nettime_driver = { + .name = "Meego 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); +} + +OFONO_PLUGIN_DEFINE(meego_nettime, "Meego Network Time Plugin", + VERSION, OFONO_PLUGIN_PRIORITY_DEFAULT, + nettime_init, nettime_exit) + -- 1.7.1