diff options
-rw-r--r-- | doc/ussd-api.txt | 64 | ||||
-rw-r--r-- | src/ussd.c | 162 |
2 files changed, 216 insertions, 10 deletions
diff --git a/doc/ussd-api.txt b/doc/ussd-api.txt new file mode 100644 index 00000000..83d3cee7 --- /dev/null +++ b/doc/ussd-api.txt @@ -0,0 +1,64 @@ +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. + + dict GetProperties() + + Returns Supplementary Services related properties. See + the properties section for available properties. + +Signals NotificationReceived(string message) + + Signal is emitted on a network-initiated USSD + request for which no response is needed. + + RequestReceived(string message) + + 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. + + PropertyChanged(string property, variant value) + + Signal is emitted whenever a property has changed. + The new value is passed as the signal argument. + +Properties string USSDState [readonly] + + Reflects the state of current USSD session. The + values have the following meanings: + + "idle" No active USSD session. + "active" A session is active between the + network and the ME, the ME is + waiting for a reply from the + network. + "awaiting-user-response" The network is waiting for the + user's response, client must + call Respond(). @@ -272,6 +272,37 @@ out: return ret; } +static const char *ussd_get_state_string(struct ofono_ussd *ussd) +{ + switch (ussd->state) { + case USSD_STATE_IDLE: + return "idle"; + case USSD_STATE_ACTIVE: + return "active"; + case USSD_STATE_USER_ACTION: + return "awaiting-user-response"; + } + + return ""; +} + +static void ussd_change_state(struct ofono_ussd *ussd, int state) +{ + const char *value; + DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = __ofono_atom_get_path(ussd->atom); + + if (state == ussd->state) + return; + + ussd->state = state; + + value = ussd_get_state_string(ussd); + ofono_dbus_signal_property_changed(conn, path, + SUPPLEMENTARY_SERVICES_INTERFACE, + "USSDState", DBUS_TYPE_STRING, &value); +} + void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str) { DBusConnection *conn = ofono_dbus_get_connection(); @@ -282,7 +313,7 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str) DBusMessageIter variant; if (status == OFONO_USSD_STATUS_NOT_SUPPORTED) { - ussd->state = USSD_STATE_IDLE; + ussd_change_state(ussd, USSD_STATE_IDLE); if (!ussd->pending) return; @@ -292,7 +323,7 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str) } if (status == OFONO_USSD_STATUS_TIMED_OUT) { - ussd->state = USSD_STATE_IDLE; + ussd_change_state(ussd, USSD_STATE_IDLE); if (!ussd->pending) return; @@ -323,12 +354,34 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *str) dbus_message_iter_close_container(&iter, &variant); if (status == OFONO_USSD_STATUS_ACTION_REQUIRED) - ussd->state = USSD_STATE_USER_ACTION; + ussd_change_state(ussd, USSD_STATE_USER_ACTION); else - ussd->state = USSD_STATE_IDLE; + ussd_change_state(ussd, USSD_STATE_IDLE); + + } else if (ussd->state == USSD_STATE_IDLE) { + const char *signal_name; + const char *path = __ofono_atom_get_path(ussd->atom); + int new_state; + + if (status == OFONO_USSD_STATUS_ACTION_REQUIRED) { + new_state = USSD_STATE_USER_ACTION; + signal_name = "RequestReceived"; + } else { + new_state = USSD_STATE_IDLE; + signal_name = "NotificationReceived"; + } + + if (!str) + str = ""; + + g_dbus_emit_signal(conn, path, + SUPPLEMENTARY_SERVICES_INTERFACE, signal_name, + DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID); + ussd_change_state(ussd, new_state); + return; } else { - ofono_error("Received an unsolicited USSD, ignoring for now..."); + ofono_error("Received an unsolicited USSD but can't handle."); DBG("USSD is: status: %d, %s", status, str); return; @@ -351,7 +404,7 @@ static void ussd_callback(const struct ofono_error *error, void *data) telephony_error_to_str(error)); if (error->type == OFONO_ERROR_TYPE_NO_ERROR) { - ussd->state = USSD_STATE_ACTIVE; + ussd_change_state(ussd, USSD_STATE_ACTIVE); return; } @@ -371,7 +424,7 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg, if (ussd->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, @@ -401,12 +454,67 @@ 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; + + if (!ussd->pending) + return; + + if (error->type == OFONO_ERROR_TYPE_NO_ERROR) { + ussd_change_state(ussd, 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); + + reply = __ofono_error_failed(ussd->pending); + __ofono_dbus_pending_reply(&ussd->pending, reply); +} + +static DBusMessage *ussd_respond(DBusConnection *conn, DBusMessage *msg, + void *data) +{ + struct ofono_ussd *ussd = data; + const char *str; + + if (ussd->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->request) + return __ofono_error_not_implemented(msg); + + ussd->pending = dbus_message_ref(msg); + + ussd->driver->request(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; DBusMessage *reply; - ussd->state = USSD_STATE_IDLE; + ussd_change_state(ussd, USSD_STATE_IDLE); if (error->type != OFONO_ERROR_TYPE_NO_ERROR) DBG("ussd cancel failed with error: %s", @@ -444,15 +552,49 @@ static DBusMessage *ussd_cancel(DBusConnection *conn, DBusMessage *msg, return NULL; } +static DBusMessage *ussd_get_properties(DBusConnection *conn, + DBusMessage *msg, void *data) +{ + struct ofono_ussd *ussd = data; + DBusMessage *reply; + DBusMessageIter iter; + DBusMessageIter dict; + const char *value; + + reply = dbus_message_new_method_return(msg); + if (!reply) + return NULL; + + dbus_message_iter_init_append(reply, &iter); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, + OFONO_PROPERTIES_ARRAY_SIGNATURE, + &dict); + + value = ussd_get_state_string(ussd); + ofono_dbus_dict_append(&dict, "USSDState", DBUS_TYPE_STRING, &value); + + dbus_message_iter_close_container(&iter, &dict); + + return reply; +} + static GDBusMethodTable ussd_methods[] = { - { "Initiate", "s", "sv", ussd_initiate, + { "Initiate", "s", "sv", ussd_initiate, + G_DBUS_METHOD_FLAG_ASYNC }, + { "Respond", "s", "", ussd_respond, G_DBUS_METHOD_FLAG_ASYNC }, - { "Cancel", "", "", ussd_cancel, + { "Cancel", "", "", ussd_cancel, G_DBUS_METHOD_FLAG_ASYNC }, + { "GetProperties", "", "a{sv}", ussd_get_properties, + 0 }, { } }; static GDBusSignalTable ussd_signals[] = { + { "NotificationReceived", "s" }, + { "RequestReceived", "s" }, + { "PropertyChanged", "sv" }, { } }; |