diff options
author | Andrzej Zaborowski <andrew.zaborowski@intel.com> | 2010-02-15 11:05:16 +0100 |
---|---|---|
committer | Denis Kenzior <denkenz@gmail.com> | 2010-02-16 10:17:40 -0600 |
commit | 740f8e3f0941e033b33c9394299e6bb5a05c72ba (patch) | |
tree | e6c14c10f8594e48f9c5cd269e6e6684de43c228 /src/ussd.c | |
parent | 400d692e6ef459fa3a98f8c2dd1f4302f39cb020 (diff) | |
download | ofono-740f8e3f0941e033b33c9394299e6bb5a05c72ba.tar.bz2 |
Handle network-initiated ussd requests.
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.
Diffstat (limited to 'src/ussd.c')
-rw-r--r-- | src/ussd.c | 162 |
1 files changed, 152 insertions, 10 deletions
@@ -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" }, { } }; |