diff --git a/Makefile.am b/Makefile.am index 6f3bdad8..a77c767c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -725,6 +725,13 @@ noinst_PROGRAMS += tools/qmi tools_qmi_SOURCES = $(qmi_sources) tools/qmi.c tools_qmi_LDADD = @GLIB_LIBS@ endif + +if MAINTAINER_MODE +noinst_PROGRAMS += tools/stktest + +tools_stktest_SOURCES = $(gdbus_sources) tools/stktest.c +tools_stktest_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ +endif endif if DUNDEE diff --git a/tools/stktest.c b/tools/stktest.c new file mode 100644 index 00000000..22a11e09 --- /dev/null +++ b/tools/stktest.c @@ -0,0 +1,300 @@ +/* + * + * oFono - Open Source Telephony + * + * Copyright (C) 2008-2011 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 + * 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 +#include +#include +#include +#include +#include + +#include + +#define OFONO_SERVICE "org.ofono" +#define STKTEST_PATH "/stktest" +#define OFONO_MANAGER_INTERFACE OFONO_SERVICE ".Manager" +#define OFONO_MODEM_INTERFACE OFONO_SERVICE ".Modem" +#define OFONO_STK_INTERFACE OFONO_SERVICE ".SimToolkit" + +static GMainLoop *main_loop = NULL; +static volatile sig_atomic_t __terminated = 0; +static DBusConnection *conn; +static gboolean ofono_running = FALSE; +static guint modem_changed_watch; +static gboolean stk_ready = FALSE; + +static gboolean has_stk_interface(DBusMessageIter *iter) +{ + DBusMessageIter entry; + + dbus_message_iter_recurse(iter, &entry); + + while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { + const char *interface; + + dbus_message_iter_get_basic(&entry, &interface); + + if (g_str_equal(interface, OFONO_STK_INTERFACE) == TRUE) + return TRUE; + + dbus_message_iter_next(&entry); + } + + return FALSE; +} + +static gboolean modem_changed(DBusConnection *conn, + DBusMessage *msg, void *user_data) +{ + DBusMessageIter iter, value; + const char *path, *key; + gboolean has_stk; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + path = dbus_message_get_path(msg); + + if (g_str_equal(STKTEST_PATH, path) == FALSE) + return TRUE; + + dbus_message_iter_get_basic(&iter, &key); + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &value); + + if (g_str_equal(key, "Interfaces") == FALSE) + return TRUE; + + has_stk = has_stk_interface(&value); + + if (stk_ready && has_stk == FALSE) { + stk_ready = FALSE; + g_print("Lost STK interface\n"); + } else if (stk_ready == FALSE && has_stk == TRUE) { + stk_ready = TRUE; + g_print("Gained STK interface\n"); + } + + return TRUE; +} + +static void get_modems_reply(DBusPendingCall *call, void *user_data) +{ + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusMessageIter iter, list; + DBusError err; + gboolean found = FALSE; + + dbus_error_init(&err); + + if (dbus_set_error_from_message(&err, reply) == TRUE) { + g_printerr("%s: %s\n", err.name, err.message); + dbus_error_free(&err); + goto done; + } + + if (dbus_message_has_signature(reply, "a(oa{sv})") == FALSE) + goto done; + + if (dbus_message_iter_init(reply, &iter) == FALSE) + goto done; + + dbus_message_iter_recurse(&iter, &list); + + while (dbus_message_iter_get_arg_type(&list) == DBUS_TYPE_STRUCT) { + DBusMessageIter entry; + const char *path; + + dbus_message_iter_recurse(&list, &entry); + dbus_message_iter_get_basic(&entry, &path); + + if (g_str_equal(path, STKTEST_PATH)) + found = TRUE; + + dbus_message_iter_next(&list); + } + +done: + dbus_message_unref(reply); + + if (found == FALSE) { + g_printerr("STK Test modem not found\n"); + g_main_loop_quit(main_loop); + return; + } + + g_print("Test modem found\n"); + + modem_changed_watch = g_dbus_add_signal_watch(conn, OFONO_SERVICE, + STKTEST_PATH, + OFONO_MODEM_INTERFACE, + "PropertyChanged", + modem_changed, + NULL, NULL); +} + +static int get_modems(DBusConnection *conn) +{ + DBusMessage *msg; + DBusPendingCall *call; + + msg = dbus_message_new_method_call(OFONO_SERVICE, "/", + OFONO_MANAGER_INTERFACE, "GetModems"); + if (msg == NULL) + return -ENOMEM; + + dbus_message_set_auto_start(msg, FALSE); + + g_print("getting modems\n"); + + if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) { + dbus_message_unref(msg); + return -EIO; + } + + dbus_message_unref(msg); + + if (call == NULL) + return -EINVAL; + + dbus_pending_call_set_notify(call, get_modems_reply, conn, NULL); + + dbus_pending_call_unref(call); + + return 0; +} + +static void ofono_connect(DBusConnection *conn, void *user_data) +{ + g_print("starting telephony interface\n"); + + ofono_running = TRUE; + + get_modems(conn); +} + +static void ofono_disconnect(DBusConnection *conn, void *user_data) +{ + g_print("stopping telephony interface\n"); + + ofono_running = FALSE; + + g_dbus_remove_watch(conn, modem_changed_watch); + modem_changed_watch = 0; +} + +static void sig_term(int sig) +{ + if (__terminated > 0) + return; + + __terminated = 1; + + g_print("Terminating\n"); + + g_main_loop_quit(main_loop); +} + +static void disconnect_callback(DBusConnection *conn, void *user_data) +{ + g_printerr("D-Bus disconnect\n"); + + g_main_loop_quit(main_loop); +} + +static gboolean option_version = FALSE; + +static GOptionEntry options[] = { + { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, + "Show version information and exit" }, + { NULL }, +}; + +int main(int argc, char **argv) +{ + GOptionContext *context; + GError *error = NULL; + DBusError err; + guint watch; + struct sigaction sa; + + context = g_option_context_new(NULL); + g_option_context_add_main_entries(context, options, NULL); + + if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) { + if (error != NULL) { + g_printerr("%s\n", error->message); + g_error_free(error); + } else + g_printerr("An unknown error occurred\n"); + exit(1); + } + + g_option_context_free(context); + + if (option_version == TRUE) { + printf("%s\n", VERSION); + exit(0); + } + + main_loop = g_main_loop_new(NULL, FALSE); + + dbus_error_init(&err); + + conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, &err); + if (conn == NULL) { + if (dbus_error_is_set(&err) == TRUE) { + fprintf(stderr, "%s\n", err.message); + dbus_error_free(&err); + } else + fprintf(stderr, "Can't register with system bus\n"); + exit(1); + } + + g_dbus_set_disconnect_function(conn, disconnect_callback, NULL, NULL); + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sig_term; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + watch = g_dbus_add_service_watch(conn, OFONO_SERVICE, + ofono_connect, ofono_disconnect, NULL, NULL); + + g_main_loop_run(main_loop); + + g_dbus_remove_watch(conn, watch); + + if (ofono_running == TRUE) + ofono_disconnect(conn, NULL); + + dbus_connection_unref(conn); + + g_main_loop_unref(main_loop); + + return 0; +}