Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.
Sign up| /* | |
| * | |
| * 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 <config.h> | |
| #endif | |
| #include <stdint.h> | |
| #include <string.h> | |
| #include <errno.h> | |
| #include <glib.h> | |
| #include <gdbus.h> | |
| #include <ell/ell.h> | |
| #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 */ | |
| bool 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; | |
| bool 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; | |
| } | |
| bool 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, | |
| bool 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; | |
| bool 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; | |
| bool 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, | |
| bool 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; | |
| bool 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; | |
| bool 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; | |
| bool 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, | |
| bool 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; | |
| bool 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, bool 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; | |
| bool 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, | |
| bool unicode_charset, int min, int max, | |
| bool 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; | |
| bool 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; | |
| bool 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, bool 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, bool 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; | |
| bool 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; | |
| } |