diff --git a/src/stk.c b/src/stk.c index bd7679c2..c804fc62 100644 --- a/src/stk.c +++ b/src/stk.c @@ -65,7 +65,7 @@ struct ofono_stk { struct stk_agent *session_agent; struct stk_agent *default_agent; struct stk_agent *current_agent; /* Always equals one of the above */ - struct stk_menu *main_menu; + struct stk_menu *main_menu, *select_item_menu; struct sms_submit_req *sms_submit_req; char *idle_mode_text; }; @@ -923,6 +923,67 @@ static gboolean handle_command_set_up_menu(const struct stk_command *cmd, return TRUE; } +static void request_menu_cb(enum stk_agent_result result, uint8_t id, + void *user_data) +{ + struct ofono_stk *stk = user_data; + static struct ofono_error error = { .type = OFONO_ERROR_TYPE_FAILURE }; + struct stk_response rsp; + + memset(&rsp, 0, sizeof(rsp)); + + switch (result) { + case STK_AGENT_RESULT_OK: + rsp.result.type = STK_RESULT_TYPE_SUCCESS; + rsp.select_item.item_id = id; + break; + + case STK_AGENT_RESULT_BACK: + rsp.result.type = STK_RESULT_TYPE_GO_BACK; + break; + + case STK_AGENT_RESULT_TIMEOUT: + rsp.result.type = STK_RESULT_TYPE_NO_RESPONSE; + break; + + case STK_AGENT_RESULT_CANCEL: + goto out; + + case STK_AGENT_RESULT_TERMINATE: + default: + rsp.result.type = STK_RESULT_TYPE_USER_TERMINATED; + break; + } + + if (stk_respond(stk, &rsp, stk_command_cb)) + stk_command_cb(&error, stk); + +out: + stk_menu_free(stk->select_item_menu); + stk->select_item_menu = NULL; +} + +static gboolean handle_command_select_item(const struct stk_command *cmd, + struct stk_response *rsp, + struct ofono_stk *stk) +{ + stk->select_item_menu = stk_menu_create_from_select_item(cmd); + + if (!stk->select_item_menu) { + rsp->result.type = STK_RESULT_TYPE_DATA_NOT_UNDERSTOOD; + + return TRUE; + } + + stk->cancel_cmd = stk_request_cancel; + + stk_agent_request_selection(stk->current_agent, stk->select_item_menu, + request_menu_cb, stk, + stk->timeout * 1000); + + return FALSE; +} + static void stk_proactive_command_cancel(struct ofono_stk *stk) { if (!stk->pending_cmd) @@ -1006,6 +1067,10 @@ void ofono_stk_proactive_command_notify(struct ofono_stk *stk, respond = handle_command_set_up_menu(stk->pending_cmd, &rsp, stk); break; + case STK_COMMAND_TYPE_SELECT_ITEM: + respond = handle_command_select_item(stk->pending_cmd, + &rsp, stk); + break; } if (respond) diff --git a/src/stkagent.c b/src/stkagent.c index 3f80ba1f..ce7ad185 100644 --- a/src/stkagent.c +++ b/src/stkagent.c @@ -52,6 +52,8 @@ struct stk_agent { ofono_bool_t is_default; GDestroyNotify destroy_notify; void *destroy_data; + + const struct stk_menu *request_selection_menu; }; #define OFONO_NAVIGATION_PREFIX OFONO_SERVICE ".Error" @@ -333,3 +335,64 @@ void append_menu_items_variant(DBusMessageIter *iter, dbus_message_iter_close_container(iter, &variant); } + +static void request_selection_cb(struct stk_agent *agent, + enum stk_agent_result result, + DBusMessage *reply) +{ + const struct stk_menu *menu = agent->request_selection_menu; + stk_agent_selection_cb cb = (stk_agent_selection_cb) agent->user_cb; + unsigned char selection, i; + + if (result != STK_AGENT_RESULT_OK) { + cb(result, 0, agent->user_data); + + return; + } + + if (dbus_message_get_args(reply, NULL, + DBUS_TYPE_BYTE, &selection, + DBUS_TYPE_INVALID) == FALSE) { + ofono_error("Can't parse the reply to RequestSelection()"); + + cb(STK_AGENT_RESULT_TERMINATE, 0, agent->user_data); + + return; + } + + for (i = 0; i < selection && menu->items[i].text; i++); + + if (i != selection) { + ofono_error("Invalid item selected"); + + cb(STK_AGENT_RESULT_TERMINATE, 0, agent->user_data); + + return; + } + + cb(result, menu->items[selection].item_id, agent->user_data); +} + +void stk_agent_request_selection(struct stk_agent *agent, + const struct stk_menu *menu, + stk_agent_selection_cb cb, + void *user_data, int timeout) +{ + dbus_int16_t default_item = menu->default_item; + DBusMessageIter iter; + + if (!stk_agent_request_start(agent, "RequestSelection", + request_selection_cb, + (stk_agent_generic_cb) cb, + user_data, timeout)) + return; + + 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); + + agent->request_selection_menu = menu; +} diff --git a/src/stkagent.h b/src/stkagent.h index 5561fa4e..a19df92f 100644 --- a/src/stkagent.h +++ b/src/stkagent.h @@ -46,6 +46,9 @@ enum stk_agent_result { typedef void (*stk_agent_generic_cb)(enum stk_agent_result result, void *user_data); +typedef void (*stk_agent_selection_cb)(enum stk_agent_result result, + uint8_t id, void *user_data); + struct stk_agent; struct stk_agent *stk_agent_new(const char *path, const char *sender, @@ -61,5 +64,10 @@ void stk_agent_set_destroy_watch(struct stk_agent *agent, GDestroyNotify notify, void stk_agent_request_cancel(struct stk_agent *agent); +void stk_agent_request_selection(struct stk_agent *agent, + const struct stk_menu *menu, + stk_agent_selection_cb cb, + void *user_data, int timeout); + void append_menu_items_variant(DBusMessageIter *iter, const struct stk_menu_item *items);