/* * * 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 #define _GNU_SOURCE #include #include #include #include #include #include "ofono.h" #include "common.h" #include "smsutil.h" #include "stkutil.h" #include "stkagent.h" #ifndef DBUS_TIMEOUT_INFINITE #define DBUS_TIMEOUT_INFINITE ((int) 0x7fffffff) #endif enum allowed_error { ALLOWED_ERROR_GO_BACK = 0x1, ALLOWED_ERROR_TERMINATE = 0x2, ALLOWED_ERROR_BUSY = 0x4, }; struct stk_agent { char *path; /* Agent Path */ char *bus; /* Agent bus */ guint disconnect_watch; /* DBus disconnect watch */ ofono_bool_t remove_on_terminate; ofono_destroy_func removed_cb; void *removed_data; DBusMessage *msg; DBusPendingCall *call; void *user_cb; void *user_data; int min_length; int max_length; ofono_bool_t hidden_entry; ofono_destroy_func user_destroy; const struct stk_menu *request_selection_menu; }; #define ERROR_PREFIX OFONO_SERVICE ".Error" #define GOBACK_ERROR ERROR_PREFIX ".GoBack" #define TERMINATE_ERROR ERROR_PREFIX ".EndSession" #define BUSY_ERROR ERROR_PREFIX ".Busy" static void stk_agent_send_noreply(struct stk_agent *agent, const char *method) { DBusConnection *conn = ofono_dbus_get_connection(); DBusMessage *message; message = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, method); if (message == NULL) return; dbus_message_set_no_reply(message, TRUE); g_dbus_send_message(conn, message); } static inline void stk_agent_send_release(struct stk_agent *agent) { stk_agent_send_noreply(agent, "Release"); } static inline void stk_agent_send_cancel(struct stk_agent *agent) { stk_agent_send_noreply(agent, "Cancel"); } static void stk_agent_request_end(struct stk_agent *agent) { if (agent->msg) { dbus_message_unref(agent->msg); agent->msg = NULL; } if (agent->call) { dbus_pending_call_unref(agent->call); agent->call = NULL; } if (agent->user_destroy) agent->user_destroy(agent->user_data); agent->user_destroy = NULL; agent->user_data = NULL; agent->user_cb = NULL; } ofono_bool_t stk_agent_matches(struct stk_agent *agent, const char *path, const char *sender) { return !strcmp(agent->path, path) && !strcmp(agent->bus, sender); } void stk_agent_set_removed_notify(struct stk_agent *agent, ofono_destroy_func destroy, void *user_data) { agent->removed_cb = destroy; agent->removed_data = user_data; } void stk_agent_request_cancel(struct stk_agent *agent) { if (agent->call == NULL) return; dbus_pending_call_cancel(agent->call); if (agent->disconnect_watch) stk_agent_send_cancel(agent); stk_agent_request_end(agent); } void stk_agent_free(struct stk_agent *agent) { DBusConnection *conn = ofono_dbus_get_connection(); stk_agent_request_cancel(agent); if (agent->disconnect_watch) { stk_agent_send_release(agent); g_dbus_remove_watch(conn, agent->disconnect_watch); agent->disconnect_watch = 0; } if (agent->removed_cb) agent->removed_cb(agent->removed_data); g_free(agent->path); g_free(agent->bus); g_free(agent); } static int check_error(struct stk_agent *agent, DBusMessage *reply, int allowed_errors, enum stk_agent_result *out_result) { DBusError err; int result = 0; dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply) == FALSE) { *out_result = STK_AGENT_RESULT_OK; return 0; } ofono_debug("SimToolkitAgent %s replied with error %s, %s", agent->path, err.name, err.message); /* Timeout is always valid */ if (g_str_equal(err.name, DBUS_ERROR_NO_REPLY)) { /* Send a Cancel() to the agent since its taking too long */ stk_agent_send_cancel(agent); *out_result = STK_AGENT_RESULT_TIMEOUT; goto out; } if ((allowed_errors & ALLOWED_ERROR_GO_BACK) && g_str_equal(err.name, GOBACK_ERROR)) { *out_result = STK_AGENT_RESULT_BACK; goto out; } if ((allowed_errors & ALLOWED_ERROR_TERMINATE) && g_str_equal(err.name, TERMINATE_ERROR)) { *out_result = STK_AGENT_RESULT_TERMINATE; goto out; } if ((allowed_errors & ALLOWED_ERROR_BUSY) && g_str_equal(err.name, BUSY_ERROR)) { *out_result = STK_AGENT_RESULT_BUSY; goto out; } result = -EINVAL; out: dbus_error_free(&err); return result; } static void stk_agent_disconnect_cb(DBusConnection *conn, void *user_data) { struct stk_agent *agent = user_data; ofono_debug("Agent exited without calling Unregister"); agent->disconnect_watch = 0; stk_agent_free(agent); } struct stk_agent *stk_agent_new(const char *path, const char *sender, ofono_bool_t remove_on_terminate) { struct stk_agent *agent = g_try_new0(struct stk_agent, 1); DBusConnection *conn = ofono_dbus_get_connection(); if (agent == NULL) return NULL; agent->path = g_strdup(path); agent->bus = g_strdup(sender); agent->remove_on_terminate = remove_on_terminate; agent->disconnect_watch = g_dbus_add_disconnect_watch(conn, sender, stk_agent_disconnect_cb, agent, NULL); return agent; } static void append_menu_items(DBusMessageIter *iter, const struct stk_menu_item *item) { DBusMessageIter array, entry; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "(sy)", &array); while (item && item->text) { dbus_message_iter_open_container(&array, DBUS_TYPE_STRUCT, NULL, &entry); dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &item->text); dbus_message_iter_append_basic(&entry, DBUS_TYPE_BYTE, &item->icon_id); dbus_message_iter_close_container(&array, &entry); item++; } dbus_message_iter_close_container(iter, &array); } void append_menu_items_variant(DBusMessageIter *iter, const struct stk_menu_item *items) { DBusMessageIter variant; dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a(sy)", &variant); append_menu_items(&variant, items); dbus_message_iter_close_container(iter, &variant); } #define CALLBACK_END() \ done: \ if (result == STK_AGENT_RESULT_TERMINATE && \ agent->remove_on_terminate) \ remove_agent = TRUE; \ else \ remove_agent = FALSE; \ \ error: \ stk_agent_request_end(agent); \ dbus_message_unref(reply); \ \ if (remove_agent) \ stk_agent_free(agent) \ static void request_selection_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; const struct stk_menu *menu = agent->request_selection_menu; stk_agent_selection_cb cb = (stk_agent_selection_cb) agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); unsigned char selection, i; enum stk_agent_result result; gboolean remove_agent; if (check_error(agent, reply, ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, 0, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_BYTE, &selection, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to RequestSelection()"); remove_agent = TRUE; goto error; } for (i = 0; i < selection && menu->items[i].text; i++); if (i != selection) { ofono_error("Invalid item selected"); remove_agent = TRUE; goto error; } cb(result, menu->items[selection].item_id, agent->user_data); CALLBACK_END(); } int stk_agent_request_selection(struct stk_agent *agent, const struct stk_menu *menu, stk_agent_selection_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); dbus_int16_t default_item = menu->default_item; DBusMessageIter iter; agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "RequestSelection"); if (agent->msg == NULL) return -ENOMEM; dbus_message_iter_init_append(agent->msg, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &menu->title); dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE, &menu->icon.id); append_menu_items(&iter, menu->items); dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT16, &default_item); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; agent->request_selection_menu = menu; dbus_pending_call_set_notify(agent->call, request_selection_cb, agent, NULL); return 0; } static void display_text_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_display_text_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; if (check_error(agent, reply, ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE | ALLOWED_ERROR_BUSY, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to DisplayText()"); remove_agent = TRUE; goto error; } cb(result, agent->user_data); CALLBACK_END(); } int stk_agent_display_text(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, ofono_bool_t urgent, stk_agent_display_text_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); dbus_bool_t priority = urgent; agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "DisplayText"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_BOOLEAN, &priority, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, display_text_cb, agent, NULL); return 0; } static void get_confirmation_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_confirmation_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; dbus_bool_t confirm; if (check_error(agent, reply, ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, FALSE, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_BOOLEAN, &confirm, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to GetConfirmation()"); remove_agent = TRUE; goto error; } cb(result, confirm, agent->user_data); CALLBACK_END(); } int stk_agent_request_confirmation(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, stk_agent_confirmation_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "RequestConfirmation"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, get_confirmation_cb, agent, NULL); return 0; } static void get_digit_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_string_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; char *digit; if (check_error(agent, reply, ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, NULL, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &digit, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to GetDigit()"); remove_agent = TRUE; goto error; } if (strlen(digit) != 1 || !strspn(digit, "0123456789*#+")) { ofono_error("Invalid character"); remove_agent = TRUE; goto error; } if (agent->hidden_entry && digit[0] == '+') { ofono_error("The character + is not allowed in this mode"); remove_agent = TRUE; goto error; } cb(result, digit, agent->user_data); CALLBACK_END(); } int stk_agent_request_digit(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, stk_agent_string_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "RequestDigit"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; agent->hidden_entry = FALSE; dbus_pending_call_set_notify(agent->call, get_digit_cb, agent, NULL); return 0; } int stk_agent_request_quick_digit(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, stk_agent_string_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "RequestQuickDigit"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; agent->hidden_entry = TRUE; dbus_pending_call_set_notify(agent->call, get_digit_cb, agent, NULL); return 0; } static void get_key_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_string_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; char *key; if (check_error(agent, reply, ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, NULL, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID) == FALSE || g_utf8_strlen(key, 10) != 1) { ofono_error("Can't parse the reply to GetKey()"); remove_agent = TRUE; goto error; } cb(result, key, agent->user_data); CALLBACK_END(); } int stk_agent_request_key(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, ofono_bool_t unicode_charset, stk_agent_string_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "RequestKey"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, get_key_cb, agent, NULL); return 0; } static void get_digits_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_string_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; char *string; int len, span; if (check_error(agent, reply, ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, NULL, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &string, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to GetDigits()"); remove_agent = TRUE; goto error; } len = strlen(string); if (len < agent->min_length || len > agent->max_length) { ofono_error("Length not acceptable"); remove_agent = TRUE; goto error; } if (agent->hidden_entry) span = strspn(string, "0123456789*#"); else span = strspn(string, "0123456789*#+"); if (span != len) { ofono_error("Invalid character found"); remove_agent = TRUE; goto error; } cb(result, string, agent->user_data); CALLBACK_END(); } int stk_agent_request_digits(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, const char *default_text, int min, int max, ofono_bool_t hidden, stk_agent_string_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); uint8_t min_val = min; uint8_t max_val = max; dbus_bool_t hidden_val = hidden; agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "RequestDigits"); if (agent->msg == NULL) return -ENOMEM; if (default_text == NULL) default_text = ""; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_STRING, &default_text, DBUS_TYPE_BYTE, &min_val, DBUS_TYPE_BYTE, &max_val, DBUS_TYPE_BOOLEAN, &hidden_val, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; agent->min_length = min_val; agent->max_length = max_val; agent->hidden_entry = hidden_val; dbus_pending_call_set_notify(agent->call, get_digits_cb, agent, NULL); return 0; } static void get_input_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_string_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; char *string; int len; if (check_error(agent, reply, ALLOWED_ERROR_GO_BACK | ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, NULL, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &string, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to GetInput()"); remove_agent = TRUE; goto error; } len = g_utf8_strlen(string, -1); if (len < agent->min_length || len > agent->max_length) { ofono_error("Length not acceptable"); remove_agent = TRUE; goto error; } cb(result, string, agent->user_data); CALLBACK_END(); } int stk_agent_request_input(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, const char *default_text, ofono_bool_t unicode_charset, int min, int max, ofono_bool_t hidden, stk_agent_string_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); uint8_t min_val = min; uint8_t max_val = max; dbus_bool_t hidden_val = hidden; agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "RequestInput"); if (agent->msg == NULL) return -ENOMEM; if (default_text == NULL) default_text = ""; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_STRING, &default_text, DBUS_TYPE_BYTE, &min_val, DBUS_TYPE_BYTE, &max_val, DBUS_TYPE_BOOLEAN, &hidden_val, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; agent->min_length = min_val; agent->max_length = max_val; agent->hidden_entry = hidden_val; dbus_pending_call_set_notify(agent->call, get_input_cb, agent, NULL); return 0; } static void confirm_call_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_confirmation_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; dbus_bool_t confirm; if (check_error(agent, reply, ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, FALSE, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_BOOLEAN, &confirm, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to ConfirmCallSetup()"); remove_agent = TRUE; goto error; } cb(result, confirm, agent->user_data); CALLBACK_END(); } int stk_agent_confirm_call(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, stk_agent_confirmation_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "ConfirmCallSetup"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, confirm_call_cb, agent, NULL); return 0; } static void play_tone_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_tone_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; if (check_error(agent, reply, ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to PlayTone()"); remove_agent = TRUE; goto error; } cb(result, agent->user_data); goto done; CALLBACK_END(); } int stk_agent_play_tone(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, ofono_bool_t vibrate, const char *tone, stk_agent_tone_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "PlayTone"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &tone, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, play_tone_cb, agent, NULL); return 0; } int stk_agent_loop_tone(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, ofono_bool_t vibrate, const char *tone, stk_agent_tone_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "LoopTone"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &tone, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, play_tone_cb, agent, NULL); return 0; } static void action_info_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; if (check_error(agent, reply, 0, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to DisplayActionInfo()"); remove_agent = TRUE; goto error; } goto done; CALLBACK_END(); } int stk_agent_display_action_info(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "DisplayActionInformation"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, DBUS_TIMEOUT_INFINITE) == FALSE || agent->call == NULL) return -EIO; dbus_pending_call_set_notify(agent->call, action_info_cb, agent, NULL); return 0; } static void confirm_launch_browser_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_confirmation_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; dbus_bool_t confirm; if (check_error(agent, reply, 0, &result) == -EINVAL) { remove_agent = TRUE; cb(STK_AGENT_RESULT_TERMINATE, FALSE, agent->user_data); goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, FALSE, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_BOOLEAN, &confirm, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to ConfirmLaunchBrowser()"); remove_agent = TRUE; goto error; } cb(result, confirm, agent->user_data); CALLBACK_END(); } int stk_agent_confirm_launch_browser(struct stk_agent *agent, const char *text, unsigned char icon_id, const char *url, stk_agent_confirmation_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "ConfirmLaunchBrowser"); if (agent->msg == NULL) return -ENOMEM; if (url == NULL) url = ""; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon_id, DBUS_TYPE_STRING, &url, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, confirm_launch_browser_cb, agent, NULL); return 0; } static void display_action_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_display_action_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; if (check_error(agent, reply, ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to DisplayAction()"); remove_agent = TRUE; goto error; } cb(result, agent->user_data); goto done; CALLBACK_END(); } int stk_agent_display_action(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, stk_agent_display_action_cb cb, void *user_data, ofono_destroy_func destroy) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "DisplayAction"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, DBUS_TIMEOUT_INFINITE) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, display_action_cb, agent, NULL); return 0; } static void confirm_open_channel_cb(DBusPendingCall *call, void *data) { struct stk_agent *agent = data; stk_agent_confirmation_cb cb = agent->user_cb; DBusMessage *reply = dbus_pending_call_steal_reply(call); enum stk_agent_result result; gboolean remove_agent; dbus_bool_t confirm; if (check_error(agent, reply, ALLOWED_ERROR_TERMINATE, &result) == -EINVAL) { remove_agent = TRUE; goto error; } if (result != STK_AGENT_RESULT_OK) { cb(result, FALSE, agent->user_data); goto done; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_BOOLEAN, &confirm, DBUS_TYPE_INVALID) == FALSE) { ofono_error("Can't parse the reply to ConfirmOpenChannel()"); remove_agent = TRUE; goto error; } cb(result, confirm, agent->user_data); CALLBACK_END(); } int stk_agent_confirm_open_channel(struct stk_agent *agent, const char *text, const struct stk_icon_id *icon, stk_agent_confirmation_cb cb, void *user_data, ofono_destroy_func destroy, int timeout) { DBusConnection *conn = ofono_dbus_get_connection(); agent->msg = dbus_message_new_method_call(agent->bus, agent->path, OFONO_SIM_APP_INTERFACE, "ConfirmOpenChannel"); if (agent->msg == NULL) return -ENOMEM; dbus_message_append_args(agent->msg, DBUS_TYPE_STRING, &text, DBUS_TYPE_BYTE, &icon->id, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(conn, agent->msg, &agent->call, timeout) == FALSE || agent->call == NULL) return -EIO; agent->user_cb = cb; agent->user_data = user_data; agent->user_destroy = destroy; dbus_pending_call_set_notify(agent->call, confirm_open_channel_cb, agent, NULL); return 0; }