Open Source Telephony
 help / color / mirror / Atom feed
* [PATCH, rfc] Handle network-initiated ussd requests.
@ 2010-02-12  4:52 Andrzej Zaborowski
  2010-02-15 17:03 ` Denis Kenzior
  0 siblings, 1 reply; 6+ messages in thread
From: Andrzej Zaborowski @ 2010-02-12  4:52 UTC (permalink / raw)
  To: ofono

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

This adds the methods on the D-bus interface to allow the
client to handle USSD requests from the network, according to 22.090.
Unfortunately this document is not clear on every point and some
details can't be implemented.  This includes reporting unsupported
request to the network, unsupported language, ME busy etc, because
there isn't an AT command for that.

To be really pedantic, the Initiate() return value and the
NotificationReceived() and RequestReceived()  signals should also
supply the language of the string.  I also first added a "Timeout"
property with default value of 10 seconds after which oFono
automatically replies "not supported" to network-initiated requests, so
that it is compliant when no client listents to the signals, but removed
it because it isn't useful.
---
 doc/ussd-api.txt |   45 ++++++++++++++++++
 include/ussd.h   |    4 ++
 src/ussd.c       |  135 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 180 insertions(+), 4 deletions(-)
 create mode 100644 doc/ussd-api.txt

diff --git a/doc/ussd-api.txt b/doc/ussd-api.txt
new file mode 100644
index 0000000..0f42b3a
--- /dev/null
+++ b/doc/ussd-api.txt
@@ -0,0 +1,45 @@
+SupplementaryServices hierarchy
+==========================
+
+Service		org.ofono
+Interface	org.ofono.SupplementaryServices
+Object path	[variable prefix]/{modem0,modem1,...}
+
+Methods		string, variant Initiate(string command)
+
+			Sends a USSD command string to the network
+			initiating a session.  When the request is handled
+			by the appropriate node of the network, the
+			method returns the response or an appropriate
+			error.  The network may be awaiting further response
+			from the ME after returning from this method and no
+			new command can be initiated until this one is
+			cancelled or ended.
+
+		void Respond(string reply)
+
+			Send a response to the network either when
+			it is awaiting further input after Initiate()
+			was called or after a network-initiated request.
+
+		void Cancel()
+
+			Cancel an ongoing USSD session, mobile- or
+			network-initiated.
+
+		void NotSupported()
+
+			Send a "not supported" response to a network's
+			request, ending current session.
+
+Signals		NotificationReceived(string attribute, variant value)
+
+			Signal is emitted on a network-initiated USSD
+			request for which no response is needed.
+
+		RequestReceived(string attribute, variant value)
+
+			Signal is emitted on a network-initiated USSD
+			request for which a response must be sent using
+			the Respond method unless it is cancelled or
+			the request is not supported.
diff --git a/include/ussd.h b/include/ussd.h
index 96e04cb..1f66de0 100644
--- a/include/ussd.h
+++ b/include/ussd.h
@@ -47,8 +47,12 @@ struct ofono_ussd_driver {
 	void (*remove)(struct ofono_ussd *ussd);
 	void (*request)(struct ofono_ussd *ussd, const char *str,
 				ofono_ussd_cb_t, void *data);
+	void (*respond)(struct ofono_ussd *ussd, const char *str,
+				ofono_ussd_cb_t, void *data);
 	void (*cancel)(struct ofono_ussd *ussd,
 				ofono_ussd_cb_t cb, void *data);
+	void (*respond_not_supported)(struct ofono_ussd *ussd,
+				ofono_ussd_cb_t cb, void *data);
 };
 
 void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str);
diff --git a/src/ussd.c b/src/ussd.c
index 4221dfa..6416ee9 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -274,6 +274,11 @@ out:
 	return ret;
 }
 
+static void ussd_not_supported_callback(const struct ofono_error *error,
+		void *data)
+{
+}
+
 void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str)
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
@@ -303,14 +308,14 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str)
 		goto out;
 	}
 
+	if (!str)
+		str = "";
+
 	/* TODO: Rework this in the Agent framework */
 	if (ussd->state == USSD_STATE_ACTIVE) {
 
 		reply = dbus_message_new_method_return(ussd->pending);
 
-		if (!str)
-			str = "";
-
 		dbus_message_iter_init_append(reply, &iter);
 
 		dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
@@ -329,10 +334,46 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str)
 		else
 			ussd->state = USSD_STATE_IDLE;
 
+	} else if (ussd->state == USSD_STATE_IDLE && ussd->pending == NULL) {
+		DBusMessage *signal;
+		const char *signal_name;
+		const char *path = __ofono_atom_get_path(ussd->atom);
+
+		if (status == OFONO_USSD_STATUS_ACTION_REQUIRED) {
+			ussd->state = USSD_STATE_USER_ACTION;
+			signal_name = "RequestReceived";
+		} else {
+			ussd->state = USSD_STATE_IDLE;
+			signal_name = "NotificationReceived";
+		}
+
+		signal = dbus_message_new_signal(path,
+				SUPPLEMENTARY_SERVICES_INTERFACE,
+				signal_name);
+
+		dbus_message_iter_init_append(signal, &iter);
+
+		dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+						&ussdstr);
+
+		dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, sig,
+							&variant);
+
+		dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING,
+						&str);
+
+		dbus_message_iter_close_container(&iter, &variant);
+
+		g_dbus_send_message(conn, signal);
+		return;
 	} else {
 		ofono_error("Received an unsolicited USSD, ignoring for now...");
 		DBG("USSD is: status: %d, %s", status, str);
 
+		if (ussd->driver->respond_not_supported)
+			ussd->driver->respond_not_supported(ussd,
+					ussd_not_supported_callback, NULL);
+
 		return;
 	}
 
@@ -380,7 +421,7 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
 	if (ussd->flags & USSD_FLAG_PENDING)
 		return __ofono_error_busy(msg);
 
-	if (ussd->state == USSD_STATE_ACTIVE)
+	if (ussd->state != USSD_STATE_IDLE)
 		return __ofono_error_busy(msg);
 
 	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
@@ -411,6 +452,64 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
+static void ussd_response_callback(const struct ofono_error *error, void *data)
+{
+	struct ofono_ussd *ussd = data;
+	DBusConnection *conn = ofono_dbus_get_connection();
+	DBusMessage *reply;
+
+	ussd->flags &= ~USSD_FLAG_PENDING;
+
+	if (!ussd->pending)
+		return;
+
+	if (error->type == OFONO_ERROR_TYPE_NO_ERROR) {
+		ussd->state = USSD_STATE_IDLE;
+
+		reply = dbus_message_new_method_return(ussd->pending);
+	} else {
+		DBG("ussd response failed with error: %s",
+				telephony_error_to_str(error));
+
+		reply = __ofono_error_failed(ussd->pending);
+	}
+
+	g_dbus_send_message(conn, reply);
+
+	dbus_message_unref(ussd->pending);
+	ussd->pending = NULL;
+}
+
+static DBusMessage *ussd_respond(DBusConnection *conn, DBusMessage *msg,
+					void *data)
+{
+	struct ofono_ussd *ussd = data;
+	const char *str;
+
+	if (ussd->flags & USSD_FLAG_PENDING)
+		return __ofono_error_busy(msg);
+
+	if (ussd->state != USSD_STATE_USER_ACTION)
+		return __ofono_error_not_active(msg);
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &str,
+					DBUS_TYPE_INVALID) == FALSE)
+		return __ofono_error_invalid_args(msg);
+
+	if (strlen(str) == 0)
+		return __ofono_error_invalid_format(msg);
+
+	if (!ussd->driver->respond)
+		return __ofono_error_not_implemented(msg);
+
+	ussd->flags |= USSD_FLAG_PENDING;
+	ussd->pending = dbus_message_ref(msg);
+
+	ussd->driver->respond(ussd, str, ussd_response_callback, ussd);
+
+	return NULL;
+}
+
 static void ussd_cancel_callback(const struct ofono_error *error, void *data)
 {
 	struct ofono_ussd *ussd = data;
@@ -458,15 +557,43 @@ static DBusMessage *ussd_cancel(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
+static DBusMessage *ussd_not_supported(DBusConnection *conn, DBusMessage *msg,
+					void *data)
+{
+	struct ofono_ussd *ussd = data;
+
+	if (ussd->flags & USSD_FLAG_PENDING)
+		return __ofono_error_busy(msg);
+
+	if (ussd->state == USSD_STATE_IDLE)
+		return __ofono_error_not_active(msg);
+
+	if (!ussd->driver->respond_not_supported)
+		return __ofono_error_not_implemented(msg);
+
+	ussd->flags |= USSD_FLAG_PENDING;
+	ussd->pending = dbus_message_ref(msg);
+
+	ussd->driver->respond_not_supported(ussd, ussd_cancel_callback, ussd);
+
+	return NULL;
+}
+
 static GDBusMethodTable ussd_methods[] = {
 	{ "Initiate",	"s",	"sv",	ussd_initiate,
 					G_DBUS_METHOD_FLAG_ASYNC },
+	{ "Respond",	"s",	"",	ussd_respond,
+					G_DBUS_METHOD_FLAG_ASYNC },
 	{ "Cancel",	"",	"",	ussd_cancel,
 					G_DBUS_METHOD_FLAG_ASYNC },
+	{ "NotSupported",	"",	"",	ussd_not_supported,
+					G_DBUS_METHOD_FLAG_ASYNC },
 	{ }
 };
 
 static GDBusSignalTable ussd_signals[] = {
+	{ "NotificationReceived",	"sv" },
+	{ "RequestReceived",		"sv" },
 	{ }
 };
 
-- 
1.6.1


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

end of thread, other threads:[~2010-02-16 16:20 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-02-12  4:52 [PATCH, rfc] Handle network-initiated ussd requests Andrzej Zaborowski
2010-02-15 17:03 ` Denis Kenzior
2010-02-15 20:12   ` Andrzej Zaborowski
2010-02-15 21:24     ` Denis Kenzior
2010-02-15 23:09       ` Andrzej Zaborowski
2010-02-16 16:20         ` Denis Kenzior

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox