summaryrefslogtreecommitdiffstats
path: root/src/stk.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stk.c')
-rw-r--r--src/stk.c200
1 files changed, 200 insertions, 0 deletions
diff --git a/src/stk.c b/src/stk.c
index 41464437..93319346 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -32,6 +32,7 @@
#include <gdbus.h>
#include <errno.h>
#include <time.h>
+#include <sys/time.h>
#include "ofono.h"
@@ -69,6 +70,7 @@ struct ofono_stk {
guint remove_agent_source;
struct sms_submit_req *sms_submit_req;
char *idle_mode_text;
+ struct timeval get_inkey_start_ts;
};
struct envelope_op {
@@ -1134,6 +1136,199 @@ static gboolean handle_command_display_text(const struct stk_command *cmd,
return stk->immediate_response;
}
+static void set_get_inkey_duration(struct stk_duration *duration,
+ struct timeval *start_ts)
+{
+ struct timeval end_ts;
+ int interval;
+
+ gettimeofday(&end_ts, NULL);
+
+ interval = (end_ts.tv_usec + 1099999 - start_ts->tv_usec) / 100000;
+ interval += (end_ts.tv_sec - start_ts->tv_sec) * 10;
+ interval -= 10;
+
+ switch (duration->unit) {
+ case STK_DURATION_TYPE_MINUTES:
+ interval = (interval + 59) / 60;
+ case STK_DURATION_TYPE_SECONDS:
+ interval = (interval + 9) / 10;
+ case STK_DURATION_TYPE_SECOND_TENTHS:
+ break;
+ }
+
+ duration->interval = interval;
+}
+
+static void request_confirmation_cb(enum stk_agent_result result,
+ gboolean confirm,
+ void *user_data)
+{
+ struct ofono_stk *stk = user_data;
+ static struct ofono_error error = { .type = OFONO_ERROR_TYPE_FAILURE };
+ struct stk_command_get_inkey *cmd = &stk->pending_cmd->get_inkey;
+ uint8_t qualifier = stk->pending_cmd->qualifier;
+ struct stk_response rsp;
+
+ switch (result) {
+ case STK_AGENT_RESULT_OK:
+ memset(&rsp, 0, sizeof(rsp));
+
+ rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+ rsp.get_inkey.text.text = confirm ? "" : NULL;
+ rsp.get_inkey.text.yesno = TRUE;
+
+ if (cmd->duration.interval) {
+ rsp.get_inkey.duration.unit = cmd->duration.unit;
+ set_get_inkey_duration(&rsp.get_inkey.duration,
+ &stk->get_inkey_start_ts);
+ }
+
+ if (stk_respond(stk, &rsp, stk_command_cb))
+ stk_command_cb(&error, stk);
+
+ break;
+
+ case STK_AGENT_RESULT_BACK:
+ send_simple_response(stk, STK_RESULT_TYPE_GO_BACK);
+ break;
+
+ case STK_AGENT_RESULT_TIMEOUT:
+ send_simple_response(stk, STK_RESULT_TYPE_NO_RESPONSE);
+ break;
+
+ case STK_AGENT_RESULT_HELP:
+ if ((qualifier & (1 << 7)) == 0) {
+ ofono_error("Help requested but not available");
+
+ send_simple_response(stk,
+ STK_RESULT_TYPE_USER_TERMINATED);
+ break;
+ }
+
+ send_simple_response(stk, STK_RESULT_TYPE_HELP_REQUESTED);
+ break;
+
+ case STK_AGENT_RESULT_TERMINATE:
+ default:
+ send_simple_response(stk, STK_RESULT_TYPE_USER_TERMINATED);
+ break;
+ }
+}
+
+static void request_key_cb(enum stk_agent_result result, char *string,
+ void *user_data)
+{
+ struct ofono_stk *stk = user_data;
+ static struct ofono_error error = { .type = OFONO_ERROR_TYPE_FAILURE };
+ struct stk_command_get_inkey *cmd = &stk->pending_cmd->get_inkey;
+ uint8_t qualifier = stk->pending_cmd->qualifier;
+ struct stk_response rsp;
+
+ switch (result) {
+ case STK_AGENT_RESULT_OK:
+ memset(&rsp, 0, sizeof(rsp));
+
+ rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+ rsp.get_inkey.text.text = string;
+
+ if (cmd->duration.interval) {
+ rsp.get_inkey.duration.unit = cmd->duration.unit;
+ set_get_inkey_duration(&rsp.get_inkey.duration,
+ &stk->get_inkey_start_ts);
+ }
+
+ if (stk_respond(stk, &rsp, stk_command_cb))
+ stk_command_cb(&error, stk);
+
+ break;
+
+ case STK_AGENT_RESULT_BACK:
+ send_simple_response(stk, STK_RESULT_TYPE_GO_BACK);
+ break;
+
+ case STK_AGENT_RESULT_TIMEOUT:
+ send_simple_response(stk, STK_RESULT_TYPE_NO_RESPONSE);
+ break;
+
+ case STK_AGENT_RESULT_HELP:
+ if ((qualifier & (1 << 7)) == 0) {
+ ofono_error("Help requested but not available");
+
+ send_simple_response(stk,
+ STK_RESULT_TYPE_USER_TERMINATED);
+ break;
+ }
+
+ send_simple_response(stk, STK_RESULT_TYPE_HELP_REQUESTED);
+ break;
+
+ case STK_AGENT_RESULT_TERMINATE:
+ default:
+ send_simple_response(stk, STK_RESULT_TYPE_USER_TERMINATED);
+ break;
+ }
+}
+
+static gboolean handle_command_get_inkey(const struct stk_command *cmd,
+ struct stk_response *rsp,
+ struct ofono_stk *stk)
+{
+ int timeout = stk->timeout * 1000;
+ const struct stk_command_get_inkey *gi = &cmd->get_inkey;
+ uint8_t qualifier = stk->pending_cmd->qualifier;
+ gboolean alphabet = (qualifier & (1 << 0)) != 0;
+ gboolean ucs2 = (qualifier & (1 << 1)) != 0;
+ gboolean yesno = (qualifier & (1 << 2)) != 0;
+ /*
+ * Note: immediate response and help parameter values are not
+ * provided by current api.
+ */
+ uint8_t icon_id = 0;
+ int err;
+
+ if (gi->duration.interval) {
+ timeout = gi->duration.interval;
+ switch (gi->duration.unit) {
+ case STK_DURATION_TYPE_MINUTES:
+ timeout *= 60;
+ case STK_DURATION_TYPE_SECONDS:
+ timeout *= 10;
+ case STK_DURATION_TYPE_SECOND_TENTHS:
+ timeout *= 100;
+ }
+ }
+
+ gettimeofday(&stk->get_inkey_start_ts, NULL);
+
+ stk->cancel_cmd = stk_request_cancel;
+
+ if (yesno)
+ err = stk_agent_request_confirmation(stk->current_agent,
+ gi->text, icon_id,
+ request_confirmation_cb,
+ stk, NULL, timeout);
+ else if (alphabet)
+ err = stk_agent_request_key(stk->current_agent, gi->text,
+ icon_id, ucs2, request_key_cb,
+ stk, NULL, timeout);
+ else
+ err = stk_agent_request_digit(stk->current_agent, gi->text,
+ icon_id, request_key_cb,
+ stk, NULL, timeout);
+
+ if (err < 0) {
+ /*
+ * We most likely got an out of memory error, tell SIM
+ * to retry
+ */
+ rsp->result.type = STK_RESULT_TYPE_TERMINAL_BUSY;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static void stk_proactive_command_cancel(struct ofono_stk *stk)
{
if (stk->immediate_response)
@@ -1268,6 +1463,11 @@ void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
&rsp, stk);
break;
+ case STK_COMMAND_TYPE_GET_INKEY:
+ respond = handle_command_get_inkey(stk->pending_cmd,
+ &rsp, stk);
+ break;
+
default:
rsp.result.type = STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD;
break;