All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] stk: Add agent registration and logic.
@ 2010-07-22 11:42 Andrzej Zaborowski
  2010-07-22 11:42 ` [PATCH 2/5] stk: Add menu related utilities Andrzej Zaborowski
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Andrzej Zaborowski @ 2010-07-22 11:42 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 12175 bytes --]

This patch adds a skeleton that command implementations use in the
subsequent patches.

Icons and text attributes are not implemented in this series, I'll
send them separately.  There are slight differences from
doc/stk-api.txt, for example org.ofono.Error.EndSession can be used
to terminate either a user-initiated or UICC-initiated session.

Should we change the ".Error" part to something like ".Navigation",
since these are not error conditions and may be confusing?
---
 src/stk.c |  396 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 396 insertions(+), 0 deletions(-)

diff --git a/src/stk.c b/src/stk.c
index 556dc68..3ccb7e9 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -46,6 +46,28 @@ struct stk_timer {
 	time_t start;
 };
 
+enum stk_agent_result {
+	STK_AGENT_RESULT_OK,
+	STK_AGENT_RESULT_BACK,
+	STK_AGENT_RESULT_TERMINATE,
+	STK_AGENT_RESULT_HELP,
+	STK_AGENT_RESULT_TIMEOUT,
+	STK_AGENT_RESULT_CANCEL,
+};
+
+struct stk_app_agent {
+	char *path;
+	char *bus;
+	DBusMessage *msg;
+	DBusPendingCall *call;
+	guint watch;
+	guint cmd_timeout;
+	void (*cmd_send)(struct ofono_stk *stk, DBusMessage *call);
+	void (*cmd_cb)(struct ofono_stk *stk, enum stk_agent_result result,
+			DBusMessage *reply);
+	struct ofono_stk *stk;
+};
+
 struct ofono_stk {
 	const struct ofono_stk_driver *driver;
 	void *driver_data;
@@ -57,6 +79,10 @@ struct ofono_stk {
 	struct stk_timer timers[8];
 	guint timers_source;
 
+	int timeout;
+	int short_timeout;
+	struct stk_app_agent *primary_agent;
+	struct stk_app_agent *default_agent;
 	struct sms_submit_req *sms_submit_req;
 	char *idle_mode_text;
 };
@@ -76,6 +102,10 @@ struct sms_submit_req {
 
 #define ENVELOPE_RETRIES_DEFAULT 5
 
+#define OFONO_NAVIGATION_PREFIX OFONO_SERVICE ".Error"
+#define OFONO_NAVIGATION_GOBACK OFONO_NAVIGATION_PREFIX ".GoBack"
+#define OFONO_NAVIGATION_TERMINATED OFONO_NAVIGATION_PREFIX ".EndSession"
+
 static void envelope_queue_run(struct ofono_stk *stk);
 static void timers_update(struct ofono_stk *stk);
 
@@ -255,8 +285,361 @@ static DBusMessage *stk_get_properties(DBusConnection *conn,
 	return reply;
 }
 
+static void app_agent_request_send_cancel(struct stk_app_agent *agent)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	DBusMessage *message;
+
+	message = dbus_message_new_method_call(agent->bus, agent->path,
+						OFONO_SIM_APP_INTERFACE,
+						"Cancel");
+	if (message == NULL)
+		return;
+
+	dbus_message_set_no_reply(message, TRUE);
+
+	g_dbus_send_message(conn, message);
+}
+
+static void app_agent_request_end(struct stk_app_agent *agent)
+{
+	agent->cmd_send = NULL;
+	agent->cmd_cb = NULL;
+
+	if (agent->cmd_timeout) {
+		g_source_remove(agent->cmd_timeout);
+		agent->cmd_timeout = 0;
+	}
+
+	if (agent->msg) {
+		dbus_message_unref(agent->msg);
+		agent->msg = NULL;
+	}
+
+	if (agent->call) {
+		dbus_pending_call_cancel(agent->call);
+		dbus_pending_call_unref(agent->call);
+		agent->call = NULL;
+	}
+}
+
+static void app_agent_request_cancel(struct stk_app_agent *agent)
+{
+	if (!agent->cmd_send)
+		return;
+
+	agent->cmd_cb(agent->stk, STK_AGENT_RESULT_CANCEL, NULL);
+
+	app_agent_request_end(agent);
+
+	app_agent_request_send_cancel(agent);
+}
+
+static void stk_agent_request_cancel(struct ofono_stk *stk)
+{
+	if (stk->primary_agent)
+		app_agent_request_cancel(stk->primary_agent);
+
+	if (stk->default_agent)
+		app_agent_request_cancel(stk->default_agent);
+}
+
+static gboolean app_agent_request_timeout(gpointer user_data)
+{
+	struct stk_app_agent *agent = user_data;
+
+	agent->cmd_timeout = 0;
+
+	agent->cmd_cb(agent->stk, STK_AGENT_RESULT_TIMEOUT, NULL);
+
+	app_agent_request_end(agent);
+
+	app_agent_request_send_cancel(agent);
+
+	return FALSE;
+}
+
+static void app_agent_request_terminate(struct stk_app_agent *agent)
+{
+	agent->cmd_cb(agent->stk, STK_AGENT_RESULT_TERMINATE, NULL);
+
+	app_agent_request_end(agent);
+}
+
+static void app_agent_remove(void *user_data)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	struct stk_app_agent *agent = user_data;
+
+	if (agent->watch) {
+		DBusMessage *message;
+
+		if (agent->cmd_cb) {
+			app_agent_request_terminate(agent);
+
+			app_agent_request_send_cancel(agent);
+		}
+
+		message = dbus_message_new_method_call(agent->bus, agent->path,
+							OFONO_SIM_APP_INTERFACE,
+							"Release");
+		if (message) {
+			dbus_message_set_no_reply(message, TRUE);
+
+			g_dbus_send_message(conn, message);
+		}
+
+		g_dbus_remove_watch(conn, agent->watch);
+		agent->watch = 0;
+	} else {
+		if (agent->cmd_cb)
+			app_agent_request_terminate(agent);
+	}
+
+	if (agent->stk->primary_agent == agent)
+		agent->stk->primary_agent = NULL;
+	if (agent->stk->default_agent == agent)
+		agent->stk->default_agent = NULL;
+
+	if (agent->remove_agent_source) {
+		g_source_remove(agent->remove_agent_source);
+		agent->remove_agent_source = 0;
+	}
+
+	g_free(agent->path);
+	g_free(agent->bus);
+	g_free(agent);
+}
+
+static gboolean app_agent_remove_cb(gpointer user_data)
+{
+	struct stk_app_agent *agent = user_data;
+
+	agent->remove_agent_source = 0;
+
+	app_agent_remove(user_data);
+
+	return FALSE;
+}
+
+static void app_agent_request_reply_handle(DBusPendingCall *call, void *data)
+{
+	struct stk_app_agent *agent = data;
+	DBusError err;
+	DBusMessage *reply = dbus_pending_call_steal_reply(call);
+	enum stk_agent_result result = STK_AGENT_RESULT_OK;
+
+	dbus_error_init(&err);
+	if (dbus_set_error_from_message(&err, reply)) {
+		ofono_error("SimAppAgent %s replied with error %s, %s",
+				agent->path, err.name, err.message);
+
+		if (g_str_has_prefix(err.name, OFONO_NAVIGATION_GOBACK))
+			result = STK_AGENT_RESULT_BACK;
+		else
+			result = STK_AGENT_RESULT_TERMINATE;
+
+		dbus_error_free(&err);
+	}
+
+	agent->cmd_cb(agent->stk, result, reply);
+
+	app_agent_request_end(agent);
+
+	dbus_message_unref(reply);
+
+	if (result != STK_AGENT_RESULT_TERMINATE)
+		return;
+
+	if (agent->stk->primary_agent != agent)
+		return;
+
+	app_agent_remove(agent);
+}
+
+static gboolean app_agent_request_send(struct stk_app_agent *agent)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+
+	/*
+	 * The cmd_send callback needs to set the method name to
+	 * something different than "Cancel".
+	 */
+	agent->msg = dbus_message_new_method_call(agent->bus, agent->path,
+							OFONO_SIM_APP_INTERFACE,
+							"Cancel");
+	if (agent->msg == NULL) {
+		ofono_error("Couldn't make a DBusMessage");
+		return FALSE;
+	}
+
+	agent->cmd_send(agent->stk, agent->msg);
+
+	if (dbus_connection_send_with_reply(conn,
+				agent->msg, &agent->call, INT_MAX) == FALSE ||
+			agent->call == NULL) {
+		dbus_message_unref(agent->msg);
+		agent->msg = NULL;
+
+		ofono_error("Couldn't send a method call");
+		return FALSE;
+	}
+
+	dbus_pending_call_set_notify(agent->call,
+					app_agent_request_reply_handle,
+					agent, NULL);
+
+	return TRUE;
+}
+
+static void app_agent_request_start(struct ofono_stk *stk,
+					void (*send)(struct ofono_stk *stk,
+							DBusMessage *call),
+					void (*cb)(struct ofono_stk *stk,
+						enum stk_agent_result result,
+						DBusMessage *reply),
+					int timeout)
+{
+	struct stk_app_agent *agent = stk->default_agent;
+
+	if (stk->primary_agent)
+		agent = stk->primary_agent;
+
+	if (agent == NULL) {
+		cb(stk, STK_AGENT_RESULT_TERMINATE, NULL);
+
+		return;
+	}
+
+	if (agent->cmd_cb)
+		app_agent_request_cancel(agent);
+
+	agent->cmd_send = send;
+	agent->cmd_cb = cb;
+
+	if (!app_agent_request_send(agent)) {
+		app_agent_request_terminate(agent);
+
+		return;
+	}
+
+	/* Use the timeout value specified in the command or the default.  */
+	if (timeout == 0)
+		timeout = stk->timeout * 1000;
+
+	if (timeout < 0)
+		return;
+
+	agent->cmd_timeout = g_timeout_add(timeout, app_agent_request_timeout,
+						agent);
+}
+
+static void app_agent_disconnect_cb(DBusConnection *conn, void *user_data)
+{
+	struct stk_app_agent *agent = user_data;
+
+	ofono_debug("Agent exited without calling Unregister");
+
+	agent->watch = 0;
+
+	app_agent_remove(user_data);
+}
+
+static struct stk_app_agent *app_agent_create(struct ofono_stk *stk,
+						const char *path,
+						const char *sender)
+{
+	struct stk_app_agent *agent = g_try_new0(struct stk_app_agent, 1);
+	DBusConnection *conn = ofono_dbus_get_connection();
+
+	if (!agent)
+		return NULL;
+
+	agent->path = g_strdup(path);
+	agent->bus = g_strdup(sender);
+	agent->stk = stk;
+
+	agent->watch = g_dbus_add_disconnect_watch(conn, sender,
+							app_agent_disconnect_cb,
+							agent, NULL);
+
+	return agent;
+}
+
+static DBusMessage *stk_register_agent(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct ofono_stk *stk = data;
+	const char *agent_path;
+
+	if (stk->default_agent)
+		return __ofono_error_busy(msg);
+
+	if (dbus_message_get_args(msg, NULL,
+					DBUS_TYPE_OBJECT_PATH, &agent_path,
+					DBUS_TYPE_INVALID) == FALSE)
+		return __ofono_error_invalid_args(msg);
+
+	stk->default_agent = app_agent_create(stk, agent_path,
+						dbus_message_get_sender(msg));
+	if (!stk->default_agent)
+		return __ofono_error_failed(msg);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *stk_unregister_agent(DBusConnection *conn,
+						DBusMessage *msg, void *data)
+{
+	struct ofono_stk *stk = data;
+	const char *agent_path;
+	const char *agent_bus = dbus_message_get_sender(msg);
+
+	if (dbus_message_get_args(msg, NULL,
+					DBUS_TYPE_OBJECT_PATH, &agent_path,
+					DBUS_TYPE_INVALID) == FALSE)
+		return __ofono_error_invalid_args(msg);
+
+	if (!stk->default_agent)
+		return __ofono_error_failed(msg);
+
+	if (strcmp(stk->default_agent->path, agent_path))
+		return __ofono_error_failed(msg);
+	if (strcmp(stk->default_agent->bus, agent_bus))
+		return __ofono_error_failed(msg);
+
+	app_agent_remove(stk->default_agent);
+
+	return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *stk_select_item(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct ofono_stk *stk = data;
+	const char *agent_path;
+	unsigned char selection;
+
+	if (stk->primary_agent)
+		return __ofono_error_busy(msg);
+
+	if (dbus_message_get_args(msg, NULL,
+					DBUS_TYPE_BYTE, &selection,
+					DBUS_TYPE_OBJECT_PATH, &agent_path,
+					DBUS_TYPE_INVALID) == FALSE)
+		return __ofono_error_invalid_args(msg);
+
+	/* TODO */
+
+	return NULL;
+}
+
 static GDBusMethodTable stk_methods[] = {
 	{ "GetProperties",		"",	"a{sv}",stk_get_properties },
+	{ "SelectItem",			"yo",	"",	stk_select_item,
+					G_DBUS_METHOD_FLAG_ASYNC },
+	{ "RegisterAgent",		"o",	"",	stk_register_agent },
+	{ "UnregisterAgent",		"o",	"",	stk_unregister_agent },
 
 	{ }
 };
@@ -576,6 +959,11 @@ static void stk_proactive_command_cancel(struct ofono_stk *stk)
 void ofono_stk_proactive_session_end_notify(struct ofono_stk *stk)
 {
 	stk_proactive_command_cancel(stk);
+
+	if (stk->primary_agent) {
+		app_agent_remove(stk->primary_agent);
+		stk->primary_agent = NULL;
+	}
 }
 
 void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
@@ -687,6 +1075,12 @@ static void stk_unregister(struct ofono_atom *atom)
 	struct ofono_modem *modem = __ofono_atom_get_modem(atom);
 	const char *path = __ofono_atom_get_path(atom);
 
+	if (stk->primary_agent)
+		app_agent_remove(stk->primary_agent);
+
+	if (stk->default_agent)
+		app_agent_remove(stk->default_agent);
+
 	if (stk->pending_cmd) {
 		stk_command_free(stk->pending_cmd);
 		stk->pending_cmd = NULL;
@@ -778,6 +1172,8 @@ void ofono_stk_register(struct ofono_stk *stk)
 
 	__ofono_atom_register(stk->atom, stk_unregister);
 
+	stk->timeout = 600; /* 10 minutes */
+	stk->short_timeout = 20; /* 20 seconds */
 	stk->envelope_q = g_queue_new();
 }
 
-- 
1.7.1.86.g0e460.dirty


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/5] stk: Add menu related utilities.
  2010-07-22 11:42 [PATCH 1/5] stk: Add agent registration and logic Andrzej Zaborowski
@ 2010-07-22 11:42 ` Andrzej Zaborowski
  2010-07-23 19:10   ` Denis Kenzior
  2010-07-22 11:42 ` [PATCH 3/5] stk: Handle the main menu Andrzej Zaborowski
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 6+ messages in thread
From: Andrzej Zaborowski @ 2010-07-22 11:42 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 3586 bytes --]

---
 src/stk.c |  104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 104 insertions(+), 0 deletions(-)

diff --git a/src/stk.c b/src/stk.c
index 3ccb7e9..22cf99b 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -55,6 +55,17 @@ enum stk_agent_result {
 	STK_AGENT_RESULT_CANCEL,
 };
 
+struct stk_menu {
+	char *title;
+	GSList *items;
+	struct stk_items_next_action_indicator next_action;
+	int default_item;
+	struct stk_text_attribute title_attr;
+	struct stk_item_text_attribute_list item_attrs;
+	gboolean soft_key;
+	gboolean has_help;
+};
+
 struct stk_app_agent {
 	char *path;
 	char *bus;
@@ -247,6 +258,99 @@ static void stk_command_cb(const struct ofono_error *error, void *data)
 	DBG("TERMINAL RESPONSE to a command reported no errors");
 }
 
+static struct stk_menu *stk_menu_create(const char *title,
+		const struct stk_text_attribute *title_attr, GSList *items,
+		const struct stk_item_text_attribute_list *item_attrs,
+		const struct stk_items_next_action_indicator *next_action,
+		int default_id, gboolean soft_key, gboolean has_help)
+{
+	struct stk_menu *ret = g_new(struct stk_menu, 1);
+	GSList *l;
+	int i;
+
+	ret->title = g_strdup(title ?: "");
+	ret->items = g_slist_copy((GSList *) items);
+	ret->default_item = -1;
+	memcpy(&ret->next_action, next_action, sizeof(ret->next_action));
+	memcpy(&ret->title_attr, title_attr, sizeof(ret->title_attr));
+	memcpy(&ret->item_attrs, item_attrs, sizeof(ret->item_attrs));
+	ret->soft_key = soft_key;
+	ret->has_help = has_help;
+
+	for (l = ret->items, i = 0; l; l = l->next, i++) {
+		struct stk_item *j = g_memdup(l->data, sizeof(*j));
+
+		j->text = g_strdup(j->text);
+		l->data = j;
+
+		if (j->id == default_id)
+			ret->default_item = i;
+	}
+
+	return ret;
+}
+
+static void stk_menu_free(struct stk_menu *menu)
+{
+	GSList *l;
+
+	for (l = menu->items; l; l = l->next) {
+		struct stk_item *i = l->data;
+
+		g_free(i->text);
+		g_free(i);
+	}
+
+	g_slist_free(menu->items);
+	g_free(menu->title);
+	g_free(menu);
+}
+
+static void append_menu_items(DBusMessageIter *iter, struct stk_menu *menu)
+{
+	DBusMessageIter variant, array, entry;
+	GSList *l;
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+						"a(sy)", &variant);
+
+	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+						"(sy)", &array);
+
+	for (l = menu->items; l; l = l->next) {
+		struct stk_item *item = l->data;
+		unsigned char icon_id = 0;
+
+		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,
+						&icon_id);
+
+		dbus_message_iter_close_container(&array, &entry);
+	}
+
+	dbus_message_iter_close_container(&variant, &array);
+
+	dbus_message_iter_close_container(iter, &variant);
+}
+
+static void append_menu(DBusMessage *msg, struct stk_menu *menu)
+{
+	dbus_int16_t default_item = menu->default_item;
+	unsigned char icon_id = 0;
+	DBusMessageIter iter;
+
+	dbus_message_iter_init_append(msg, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &menu->title);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE, &icon_id);
+	append_menu_items(&iter, menu);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT16, &default_item);
+}
+
 static void stk_alpha_id_set(struct ofono_stk *stk, const char *text)
 {
 	/* TODO */
-- 
1.7.1.86.g0e460.dirty


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/5] stk: Handle the main menu.
  2010-07-22 11:42 [PATCH 1/5] stk: Add agent registration and logic Andrzej Zaborowski
  2010-07-22 11:42 ` [PATCH 2/5] stk: Add menu related utilities Andrzej Zaborowski
@ 2010-07-22 11:42 ` Andrzej Zaborowski
  2010-07-22 11:42 ` [PATCH 4/5] stk: Handle the Select Item proactive command Andrzej Zaborowski
  2010-07-22 11:42 ` [PATCH 5/5] stk: Handle the Display Text " Andrzej Zaborowski
  3 siblings, 0 replies; 6+ messages in thread
From: Andrzej Zaborowski @ 2010-07-22 11:42 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 7425 bytes --]

---
 src/stk.c |  183 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 181 insertions(+), 2 deletions(-)

diff --git a/src/stk.c b/src/stk.c
index 22cf99b..17daa00 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -86,6 +86,7 @@ struct ofono_stk {
 	struct stk_command *pending_cmd;
 	void (*cancel_cmd)(struct ofono_stk *stk);
 	GQueue *envelope_q;
+	DBusMessage *pending;
 
 	struct stk_timer timers[8];
 	guint timers_source;
@@ -94,6 +95,8 @@ struct ofono_stk {
 	int short_timeout;
 	struct stk_app_agent *primary_agent;
 	struct stk_app_agent *default_agent;
+	struct stk_menu *main_menu;
+	gboolean in_session;
 	struct sms_submit_req *sms_submit_req;
 	char *idle_mode_text;
 };
@@ -351,6 +354,65 @@ static void append_menu(DBusMessage *msg, struct stk_menu *menu)
 	dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT16, &default_item);
 }
 
+static void emit_menu_changed(struct ofono_stk *stk)
+{
+	static struct stk_menu no_menu = {
+		.title = "",
+		.items = NULL,
+		.has_help = FALSE,
+		.default_item = -1,
+	};
+	DBusConnection *conn = ofono_dbus_get_connection();
+	const char *path = __ofono_atom_get_path(stk->atom);
+	struct stk_menu *menu = &no_menu;
+	DBusMessage *signal;
+	DBusMessageIter iter;
+	char *name = "MainMenu";
+
+	if (stk->main_menu && !stk->in_session)
+		menu = stk->main_menu;
+
+	ofono_dbus_signal_property_changed(conn, path,
+						OFONO_STK_INTERFACE,
+						"MainMenuTitle",
+						DBUS_TYPE_STRING, &menu->title);
+
+	signal = dbus_message_new_signal(path, OFONO_STK_INTERFACE,
+						"PropertyChanged");
+	if (!signal) {
+		ofono_error("Unable to allocate new %s.PropertyChanged signal",
+				OFONO_SIM_APP_INTERFACE);
+
+		return;
+	}
+
+	dbus_message_iter_init_append(signal, &iter);
+
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+	append_menu_items(&iter, menu);
+
+	g_dbus_send_message(conn, signal);
+}
+
+static void dict_append_menu(DBusMessageIter *dict, struct stk_menu *menu)
+{
+	DBusMessageIter entry;
+	const char *key = "MainMenu";
+
+	ofono_dbus_dict_append(dict, "MainMenuTitle",
+				DBUS_TYPE_STRING, &menu->title);
+
+	dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+						NULL, &entry);
+
+	dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+	append_menu_items(&entry, menu);
+
+	dbus_message_iter_close_container(dict, &entry);
+}
+
 static void stk_alpha_id_set(struct ofono_stk *stk, const char *text)
 {
 	/* TODO */
@@ -384,6 +446,9 @@ static DBusMessage *stk_get_properties(DBusConnection *conn,
 	ofono_dbus_dict_append(&dict, "IdleModeText",
 				DBUS_TYPE_STRING, &idle_mode_text);
 
+	if (stk->main_menu && !stk->in_session)
+		dict_append_menu(&dict, stk->main_menu);
+
 	dbus_message_iter_close_container(&iter, &dict);
 
 	return reply;
@@ -717,14 +782,69 @@ static DBusMessage *stk_unregister_agent(DBusConnection *conn,
 	return dbus_message_new_method_return(msg);
 }
 
+static void menu_selection_envelope_cb(struct ofono_stk *stk, gboolean ok,
+					const unsigned char *data, int len)
+{
+	unsigned char selection;
+	const char *agent_path;
+	DBusMessage *reply;
+
+	if (!ok) {
+		ofono_error("Sending Menu Selection to UICC failed");
+
+		reply = __ofono_error_failed(stk->pending);
+
+		goto out;
+	}
+
+	if (len)
+		ofono_error("Menu Selection returned %i bytes of unwanted data",
+				len);
+
+	DBG("Menu Selection envelope submission gave no error");
+
+	if (dbus_message_get_args(stk->pending, NULL,
+					DBUS_TYPE_BYTE, &selection,
+					DBUS_TYPE_OBJECT_PATH, &agent_path,
+					DBUS_TYPE_INVALID) == FALSE) {
+		reply = __ofono_error_failed(stk->pending);
+
+		goto out;
+	}
+
+	stk->primary_agent = app_agent_create(stk, agent_path,
+					dbus_message_get_sender(stk->pending));
+	if (!stk->primary_agent) {
+		reply = __ofono_error_failed(stk->pending);
+
+		goto out;
+	}
+
+	reply = dbus_message_new_method_return(stk->pending);
+
+	if (!stk->in_session) {
+		stk->in_session = TRUE;
+		emit_menu_changed(stk);
+	}
+
+out:
+	__ofono_dbus_pending_reply(&stk->pending, reply);
+}
+
 static DBusMessage *stk_select_item(DBusConnection *conn,
 					DBusMessage *msg, void *data)
 {
 	struct ofono_stk *stk = data;
 	const char *agent_path;
 	unsigned char selection;
+	struct stk_envelope e;
+	struct stk_menu *menu = stk->main_menu;
+	struct stk_item *item = NULL;
 
-	if (stk->primary_agent)
+	if (stk->pending)
+		return __ofono_error_busy(msg);
+
+	if (stk->primary_agent || !menu)
 		return __ofono_error_busy(msg);
 
 	if (dbus_message_get_args(msg, NULL,
@@ -733,7 +853,20 @@ static DBusMessage *stk_select_item(DBusConnection *conn,
 					DBUS_TYPE_INVALID) == FALSE)
 		return __ofono_error_invalid_args(msg);
 
-	/* TODO */
+	item = g_slist_nth_data(menu->items, selection);
+	if (!item)
+		return __ofono_error_invalid_format(msg);
+
+	memset(&e, 0, sizeof(e));
+	e.type = STK_ENVELOPE_TYPE_MENU_SELECTION;
+	e.src = STK_DEVICE_IDENTITY_TYPE_KEYPAD,
+	e.menu_selection.item_id = item->id;
+	e.menu_selection.help_request = FALSE;
+
+	if (stk_send_envelope(stk, &e, menu_selection_envelope_cb, 0))
+		return __ofono_error_failed(msg);
+
+	stk->pending = dbus_message_ref(msg);
 
 	return NULL;
 }
@@ -1047,6 +1180,38 @@ static gboolean handle_command_poll_interval(const struct stk_command *cmd,
 	return TRUE;
 }
 
+static gboolean handle_command_set_up_menu(const struct stk_command *cmd,
+						struct stk_response *rsp,
+						struct ofono_stk *stk)
+{
+	gboolean soft_key = (cmd->qualifier & (1 << 0)) != 0;
+	gboolean has_help = (cmd->qualifier & (1 << 7)) != 0;
+
+	if (stk->main_menu) {
+		stk_menu_free(stk->main_menu);
+		stk->main_menu = NULL;
+	}
+
+	if (cmd->setup_menu.items == NULL)
+		goto out;
+
+	stk->main_menu = stk_menu_create(cmd->setup_menu.alpha_id,
+					&cmd->setup_menu.text_attr,
+					cmd->setup_menu.items,
+					&cmd->setup_menu.item_text_attr_list,
+					&cmd->setup_menu.next_act,
+					0, soft_key, has_help);
+
+	if (!stk->main_menu)
+		rsp->result.type = STK_RESULT_TYPE_DATA_NOT_UNDERSTOOD;
+
+out:
+	if (!stk->in_session)
+		emit_menu_changed(stk);
+
+	return TRUE;
+}
+
 static void stk_proactive_command_cancel(struct ofono_stk *stk)
 {
 	if (!stk->pending_cmd)
@@ -1068,6 +1233,11 @@ void ofono_stk_proactive_session_end_notify(struct ofono_stk *stk)
 		app_agent_remove(stk->primary_agent);
 		stk->primary_agent = NULL;
 	}
+
+	if (stk->in_session) {
+		stk->in_session = FALSE;
+		emit_menu_changed(stk);
+	}
 }
 
 void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
@@ -1128,6 +1298,10 @@ void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
 			respond = handle_command_poll_interval(stk->pending_cmd,
 								&rsp, stk);
 			break;
+		case STK_COMMAND_TYPE_SETUP_MENU:
+			respond = handle_command_set_up_menu(stk->pending_cmd,
+								&rsp, stk);
+			break;
 		}
 
 		if (respond)
@@ -1200,6 +1374,11 @@ static void stk_unregister(struct ofono_atom *atom)
 		stk->timers_source = 0;
 	}
 
+	if (stk->main_menu) {
+		stk_menu_free(stk->main_menu);
+		stk->main_menu = NULL;
+	}
+
 	g_queue_foreach(stk->envelope_q, (GFunc) g_free, NULL);
 	g_queue_free(stk->envelope_q);
 
-- 
1.7.1.86.g0e460.dirty


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/5] stk: Handle the Select Item proactive command.
  2010-07-22 11:42 [PATCH 1/5] stk: Add agent registration and logic Andrzej Zaborowski
  2010-07-22 11:42 ` [PATCH 2/5] stk: Add menu related utilities Andrzej Zaborowski
  2010-07-22 11:42 ` [PATCH 3/5] stk: Handle the main menu Andrzej Zaborowski
@ 2010-07-22 11:42 ` Andrzej Zaborowski
  2010-07-22 11:42 ` [PATCH 5/5] stk: Handle the Display Text " Andrzej Zaborowski
  3 siblings, 0 replies; 6+ messages in thread
From: Andrzej Zaborowski @ 2010-07-22 11:42 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 3730 bytes --]

---
 src/stk.c |  115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 114 insertions(+), 1 deletions(-)

diff --git a/src/stk.c b/src/stk.c
index 17daa00..563bedd 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -95,7 +95,7 @@ struct ofono_stk {
 	int short_timeout;
 	struct stk_app_agent *primary_agent;
 	struct stk_app_agent *default_agent;
-	struct stk_menu *main_menu;
+	struct stk_menu *main_menu, *select_item_menu;
 	gboolean in_session;
 	struct sms_submit_req *sms_submit_req;
 	char *idle_mode_text;
@@ -1212,6 +1212,115 @@ out:
 	return TRUE;
 }
 
+static void request_menu_send(struct ofono_stk *stk, DBusMessage *call)
+{
+	struct stk_menu *menu = stk->select_item_menu;
+
+	dbus_message_set_member(call, "RequestSelection");
+
+	append_menu(call, menu);
+}
+
+static void request_menu_cb(struct ofono_stk *stk,
+				enum stk_agent_result result,
+				DBusMessage *reply)
+{
+	enum stk_result_type type;
+	unsigned char selection;
+	struct stk_menu *menu = stk->select_item_menu;
+	struct stk_item *item = NULL;
+	struct stk_response rsp;
+	struct ofono_error error = { .type = OFONO_ERROR_TYPE_FAILURE };
+
+	switch (result) {
+	case STK_AGENT_RESULT_OK:
+		type = STK_RESULT_TYPE_SUCCESS;
+		break;
+
+	case STK_AGENT_RESULT_BACK:
+		type = STK_RESULT_TYPE_GO_BACK;
+		goto send;
+
+	case STK_AGENT_RESULT_TIMEOUT:
+		type = STK_RESULT_TYPE_NO_RESPONSE;
+		goto send;
+
+	case STK_AGENT_RESULT_TERMINATE:
+	default:
+		type = STK_RESULT_TYPE_USER_TERMINATED;
+		goto send;
+
+	case STK_AGENT_RESULT_CANCEL:
+		goto out;
+	}
+
+	if (dbus_message_get_args(reply, NULL,
+					DBUS_TYPE_BYTE, &selection,
+					DBUS_TYPE_INVALID) == FALSE) {
+		type = STK_RESULT_TYPE_USER_TERMINATED;
+
+		ofono_error("Can't parse the reply to SelectItem()");
+		goto send;
+	}
+
+	item = g_slist_nth_data(menu->items, selection);
+	if (!item) {
+		type = STK_RESULT_TYPE_USER_TERMINATED;
+		ofono_error("Invalid item selected");
+	}
+
+send:
+	memset(&rsp, 0, sizeof(rsp));
+	rsp.result.type = type;
+
+	if (item)
+		rsp.select_item.item_id = item->id;
+
+	if (stk_respond(stk, &rsp, stk_command_cb))
+		stk_command_cb(&error, stk);
+
+out:
+	stk_menu_free(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)
+{
+	gboolean soft_key = (cmd->qualifier & (1 << 2)) != 0;
+	gboolean has_help = (cmd->qualifier & (1 << 7)) != 0;
+
+	stk->select_item_menu = stk_menu_create(
+					cmd->select_item.alpha_id,
+					&cmd->select_item.text_attr,
+					cmd->select_item.items,
+					&cmd->select_item.item_text_attr_list,
+					&cmd->select_item.next_act,
+					cmd->select_item.item_id,
+					soft_key, has_help);
+
+	if (!stk->select_item_menu) {
+		rsp->result.type = STK_RESULT_TYPE_DATA_NOT_UNDERSTOOD;
+
+		return TRUE;
+	}
+
+	if (!stk->in_session) {
+		stk->in_session = TRUE;
+
+		if (stk->main_menu)
+			emit_menu_changed(stk);
+	}
+
+	app_agent_request_start(stk,
+				request_menu_send, request_menu_cb, 0);
+
+	stk->cancel_cmd = stk_agent_request_cancel;
+
+	return FALSE;
+}
+
 static void stk_proactive_command_cancel(struct ofono_stk *stk)
 {
 	if (!stk->pending_cmd)
@@ -1302,6 +1411,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)
-- 
1.7.1.86.g0e460.dirty


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 5/5] stk: Handle the Display Text proactive command.
  2010-07-22 11:42 [PATCH 1/5] stk: Add agent registration and logic Andrzej Zaborowski
                   ` (2 preceding siblings ...)
  2010-07-22 11:42 ` [PATCH 4/5] stk: Handle the Select Item proactive command Andrzej Zaborowski
@ 2010-07-22 11:42 ` Andrzej Zaborowski
  3 siblings, 0 replies; 6+ messages in thread
From: Andrzej Zaborowski @ 2010-07-22 11:42 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 5999 bytes --]

---
 src/stk.c |  164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 158 insertions(+), 6 deletions(-)

diff --git a/src/stk.c b/src/stk.c
index 563bedd..f1717f0 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -77,6 +77,7 @@ struct stk_app_agent {
 	void (*cmd_cb)(struct ofono_stk *stk, enum stk_agent_result result,
 			DBusMessage *reply);
 	struct ofono_stk *stk;
+	guint remove_agent_source;
 };
 
 struct ofono_stk {
@@ -99,6 +100,7 @@ struct ofono_stk {
 	gboolean in_session;
 	struct sms_submit_req *sms_submit_req;
 	char *idle_mode_text;
+	gboolean session_ended;
 };
 
 struct envelope_op {
@@ -1321,6 +1323,125 @@ static gboolean handle_command_select_item(const struct stk_command *cmd,
 	return FALSE;
 }
 
+static void request_text_send(struct ofono_stk *stk, DBusMessage *call)
+{
+	struct stk_command_display_text *dt = &stk->pending_cmd->display_text;
+	uint8_t qualifier = stk->pending_cmd->qualifier;
+	dbus_bool_t confirm = (qualifier & (1 << 7)) != 0;
+	dbus_bool_t priority = (qualifier & (1 << 0)) != 0;
+	unsigned char icon_id = 0;
+
+	dbus_message_set_member(call, "DisplayText");
+
+	dbus_message_append_args(call,
+					DBUS_TYPE_STRING, &dt->text,
+					DBUS_TYPE_BYTE, &icon_id,
+					DBUS_TYPE_BOOLEAN, &priority,
+					DBUS_TYPE_BOOLEAN, &confirm,
+					DBUS_TYPE_INVALID);
+}
+
+static void request_text_cb(struct ofono_stk *stk, enum stk_agent_result result,
+				DBusMessage *reply)
+{
+	gboolean confirm;
+	enum stk_result_type type = STK_RESULT_TYPE_SUCCESS;
+	struct stk_response rsp;
+	struct ofono_error error = { .type = OFONO_ERROR_TYPE_FAILURE };
+
+	/*
+	 * Check if we have already responded to the proactive command
+	 * because immediate response was requested.
+	 */
+	if (!stk->pending_cmd || stk->pending_cmd->type !=
+			STK_COMMAND_TYPE_DISPLAY_TEXT ||
+			stk->pending_cmd->display_text.immediate_response) {
+		/*
+		 * If session has ended in the meantime now is the time
+		 * to go back to main menu or close the application
+		 * window.
+		 */
+		if (stk->session_ended && stk->primary_agent)
+			stk->primary_agent->remove_agent_source =
+				g_timeout_add(0, app_agent_remove_cb,
+						stk->primary_agent);
+
+		return;
+	}
+
+	switch (result) {
+	case STK_AGENT_RESULT_OK:
+		break;
+
+	case STK_AGENT_RESULT_BACK:
+		type = STK_RESULT_TYPE_GO_BACK;
+		goto send;
+
+	case STK_AGENT_RESULT_TIMEOUT:
+		confirm = (stk->pending_cmd->qualifier & (1 << 7)) != 0;
+		if (confirm)
+			type = STK_RESULT_TYPE_NO_RESPONSE;
+
+		goto send;
+
+	case STK_AGENT_RESULT_TERMINATE:
+	default:
+		type = STK_RESULT_TYPE_USER_TERMINATED;
+		goto send;
+
+	case STK_AGENT_RESULT_CANCEL:
+		return;
+	}
+
+	if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INVALID) == FALSE) {
+		type = STK_RESULT_TYPE_USER_TERMINATED;
+
+		ofono_error("Reply not understood");
+	}
+
+send:
+	memset(&rsp, 0, sizeof(rsp));
+	rsp.result.type = type;
+
+	if (stk_respond(stk, &rsp, stk_command_cb))
+		stk_command_cb(&error, stk);
+}
+
+static gboolean handle_command_display_text(const struct stk_command *cmd,
+						struct stk_response *rsp,
+						struct ofono_stk *stk)
+{
+	int timeout = stk->short_timeout * 1000;
+
+	if (cmd->display_text.duration.interval) {
+		timeout = cmd->display_text.duration.interval;
+		switch (cmd->display_text.duration.unit) {
+		case STK_DURATION_TYPE_MINUTES:
+			timeout *= 60;
+		case STK_DURATION_TYPE_SECONDS:
+			timeout *= 10;
+		case STK_DURATION_TYPE_SECOND_TENTHS:
+			timeout *= 100;
+		}
+	}
+
+	if (!stk->in_session) {
+		stk->in_session = TRUE;
+
+		if (stk->main_menu)
+			emit_menu_changed(stk);
+	}
+
+	app_agent_request_start(stk,
+				request_text_send, request_text_cb, timeout);
+
+	stk->session_ended = FALSE;
+
+	stk->cancel_cmd = stk_agent_request_cancel;
+
+	return cmd->display_text.immediate_response;
+}
+
 static void stk_proactive_command_cancel(struct ofono_stk *stk)
 {
 	if (!stk->pending_cmd)
@@ -1338,15 +1459,42 @@ void ofono_stk_proactive_session_end_notify(struct ofono_stk *stk)
 {
 	stk_proactive_command_cancel(stk);
 
-	if (stk->primary_agent) {
-		app_agent_remove(stk->primary_agent);
-		stk->primary_agent = NULL;
-	}
-
 	if (stk->in_session) {
 		stk->in_session = FALSE;
-		emit_menu_changed(stk);
+
+		if (stk->main_menu)
+			emit_menu_changed(stk);
 	}
+
+	if (!stk->primary_agent)
+		return;
+
+	/*
+	 * Go back to main menu, except when a DisplayText command has
+	 * been issued with the Immediate Response flag set (TS 102.223
+	 * Section 6.9):
+	 * "If the text is to be sustained, the terminal shall display
+	 * the text of applicable DISPLAY TEXT commands beyond the sending
+	 * of the TERMINAL RESPONSE and possibly beyond the end of the
+	 * proactive session.
+	 *
+	 * If a variable display timeout was indicated for a DISPLAY TEXT
+	 * command, then the session releases the display back into terminal
+	 * control no later then the period stated by the duration. If the
+	 * text is to be sustained beyond an immediate response, the
+	 * terminal shall display the text for a period that does not
+	 * exceed the duration."
+	 *
+	 * For this case we set a flag and when the text stops being
+	 * displayed we will make sure to go to main menu then.
+	 */
+	if (!stk->pending_cmd && stk->primary_agent->cmd_cb) {
+		stk->session_ended = TRUE;
+
+		return;
+	}
+
+	app_agent_remove(stk->primary_agent);
 }
 
 void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
@@ -1415,6 +1563,10 @@ void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
 			respond = handle_command_select_item(stk->pending_cmd,
 								&rsp, stk);
 			break;
+		case STK_COMMAND_TYPE_DISPLAY_TEXT:
+			respond = handle_command_display_text(stk->pending_cmd,
+								&rsp, stk);
+			break;
 		}
 
 		if (respond)
-- 
1.7.1.86.g0e460.dirty


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/5] stk: Add menu related utilities.
  2010-07-22 11:42 ` [PATCH 2/5] stk: Add menu related utilities Andrzej Zaborowski
@ 2010-07-23 19:10   ` Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2010-07-23 19:10 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 562 bytes --]

Hi Andrew,

> +static struct stk_menu *stk_menu_create(const char *title,
> +		const struct stk_text_attribute *title_attr, GSList *items,
> +		const struct stk_item_text_attribute_list *item_attrs,
> +		const struct stk_items_next_action_indicator *next_action,
> +		int default_id, gboolean soft_key, gboolean has_help)
> +{

I suggest breaking up this giant constructor with many arguments into
two functions.  One that takes a setup_menu object and one that takes a
select_item object.  Then fills in the items appropriately.

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-07-23 19:10 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-07-22 11:42 [PATCH 1/5] stk: Add agent registration and logic Andrzej Zaborowski
2010-07-22 11:42 ` [PATCH 2/5] stk: Add menu related utilities Andrzej Zaborowski
2010-07-23 19:10   ` Denis Kenzior
2010-07-22 11:42 ` [PATCH 3/5] stk: Handle the main menu Andrzej Zaborowski
2010-07-22 11:42 ` [PATCH 4/5] stk: Handle the Select Item proactive command Andrzej Zaborowski
2010-07-22 11:42 ` [PATCH 5/5] stk: Handle the Display Text " Andrzej Zaborowski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.