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

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to