summaryrefslogtreecommitdiffstats
path: root/src/ussd.c
diff options
context:
space:
mode:
authorAndrzej Zaborowski <andrew.zaborowski@intel.com>2010-02-15 11:05:16 +0100
committerDenis Kenzior <denkenz@gmail.com>2010-02-16 10:17:40 -0600
commit740f8e3f0941e033b33c9394299e6bb5a05c72ba (patch)
treee6c14c10f8594e48f9c5cd269e6e6684de43c228 /src/ussd.c
parent400d692e6ef459fa3a98f8c2dd1f4302f39cb020 (diff)
downloadofono-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.c162
1 files changed, 152 insertions, 10 deletions
diff --git a/src/ussd.c b/src/ussd.c
index 470634a9..99335333 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -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" },
{ }
};