[RFC] HFP support into oFono and BlueZ
by Gustavo F. Padovan
Hi,
These patches implement the new API for the Audio Gateway in BlueZ. It
follows the last version of the HandsfreeGateway and HandsfreeAgent
Intefaces API.
The first two patches is for BlueZ and the other for oFono. You can
test it with using enable-modem and test-voicecall scripts into the
test dir of oFono.
Feel free to test it and send me your comments. We have some bugs yet.
The audio part is not working yet. We are going to work on pulseaudio
this week to get this done soon.
Regards,
--
Gustavo F. Padovan
ProFUSION embedded systems - http://profusion.mobi
8 years, 6 months
[PATCH 1/3] hfp: create modem for new devices paired on runtime
by Gustavo F. Padovan
It listens the Paired property to create a modem to the recently paired
devices. It also renames added_watch to adapter_watch, a more proper
name.
---
plugins/hfp.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/plugins/hfp.c b/plugins/hfp.c
index 981b05b..3e41342 100644
--- a/plugins/hfp.c
+++ b/plugins/hfp.c
@@ -66,6 +66,7 @@ static const char *cmer_prefix[] = { "+CMER:", NULL };
static const char *chld_prefix[] = { "+CHLD:", NULL };
static DBusConnection *connection;
+static GHashTable *uuid_hash = NULL;
static void hfp_debug(const char *str, void *user_data)
{
@@ -427,6 +428,7 @@ static int hfp_create_modem(const char *device)
{
struct ofono_modem *modem;
struct hfp_data *data;
+ const char *path;
ofono_info("Using device: %s", device);
@@ -451,6 +453,9 @@ static int hfp_create_modem(const char *device)
ofono_modem_set_data(modem, data);
ofono_modem_register(modem);
+ path = ofono_modem_get_path(modem);
+ g_hash_table_insert(uuid_hash, g_strdup(device), g_strdup(path));
+
return 0;
free:
@@ -465,6 +470,9 @@ static void parse_uuids(DBusMessageIter *i, const char *device)
DBusMessageIter variant, ai;
const char *value;
+ if (g_hash_table_lookup(uuid_hash, device))
+ return;
+
dbus_message_iter_recurse(i, &variant);
dbus_message_iter_recurse(&variant, &ai);
@@ -624,6 +632,33 @@ static gboolean adapter_added(DBusConnection *connection, DBusMessage *message,
return TRUE;
}
+static gboolean uuid_emitted(DBusConnection *connection, DBusMessage *message,
+ void *user_data)
+{
+ const char *device, *property;
+ DBusMessageIter iter;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return FALSE;
+
+ dbus_message_iter_get_basic(&iter, &property);
+ if (g_str_equal(property, "UUIDs") == FALSE)
+ return TRUE;
+
+ if (!dbus_message_iter_next(&iter))
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return FALSE;
+
+ device = dbus_message_get_path(message);
+ parse_uuids(&iter, device);
+
+ return TRUE;
+}
+
static void list_adapters_cb(DBusPendingCall *call, gpointer user_data)
{
DBusError err;
@@ -725,6 +760,8 @@ static void hfp_remove(struct ofono_modem *modem)
hfp_unregister_ofono_handsfree(modem);
+ g_hash_table_remove(uuid_hash, data->handsfree_path);
+
g_free(data->handsfree_path);
g_free(data);
@@ -798,7 +835,8 @@ static struct ofono_modem_driver hfp_driver = {
.post_sim = hfp_post_sim,
};
-static guint added_watch;
+static guint adapter_watch;
+static guint uuid_watch;
static int hfp_init(void)
{
@@ -809,12 +847,21 @@ static int hfp_init(void)
connection = ofono_dbus_get_connection();
- added_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ adapter_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
BLUEZ_MANAGER_INTERFACE,
"AdapterAdded",
adapter_added, NULL, NULL);
- if (added_watch == 0) {
+ uuid_watch = g_dbus_add_signal_watch(connection, NULL, NULL,
+ BLUEZ_DEVICE_INTERFACE,
+ "PropertyChanged",
+ uuid_emitted, NULL, NULL);
+
+
+ uuid_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ if (adapter_watch == 0 || uuid_watch == 0) {
err = -EIO;
goto remove;
}
@@ -828,7 +875,9 @@ static int hfp_init(void)
return 0;
remove:
- g_dbus_remove_watch(connection, added_watch);
+ g_dbus_remove_watch(connection, adapter_watch);
+ g_dbus_remove_watch(connection, uuid_watch);
+ g_hash_table_destroy(uuid_hash);
dbus_connection_unref(connection);
@@ -837,9 +886,12 @@ remove:
static void hfp_exit(void)
{
- g_dbus_remove_watch(connection, added_watch);
+ g_dbus_remove_watch(connection, adapter_watch);
+ g_dbus_remove_watch(connection, uuid_watch);
ofono_modem_driver_unregister(&hfp_driver);
+
+ g_hash_table_destroy(uuid_hash);
}
OFONO_PLUGIN_DEFINE(hfp, "Hands-Free Profile Plugins", VERSION,
--
1.6.4.4
10 years, 7 months
[PATCH 1/4] Do not trigger user disconnect at g_at_shutdown
by Zhenhua Zhang
Similar to gatchat, introduce read_watcher_destroy_notify and do
not trigger user disconnect at g_at_shutdown. Delay destroy of
gatserver until read_watcher is destroyed.
---
gatchat/gatserver.c | 42 ++++++++++++++++++++++++++++--------------
1 files changed, 28 insertions(+), 14 deletions(-)
diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
index d131b0c..95a9e8f 100644
--- a/gatchat/gatserver.c
+++ b/gatchat/gatserver.c
@@ -89,7 +89,7 @@ struct _GAtServer {
gint ref_count; /* Ref count */
struct v250_settings v250; /* V.250 command setting */
GIOChannel *channel; /* Server IO */
- int server_watch; /* Watch for server IO */
+ guint read_watch; /* GSource read id, 0 if none */
guint read_so_far; /* Number of bytes processed */
GAtDisconnectFunc user_disconnect; /* User disconnect func */
gpointer user_disconnect_data; /* User disconnect data */
@@ -98,6 +98,7 @@ struct _GAtServer {
struct ring_buffer *read_buf; /* Current read buffer */
guint max_read_attempts; /* Max reads per select */
enum ParserState parser_state;
+ gboolean destroyed; /* Re-entrancy guard */
};
static void g_at_server_send_result(GAtServer *server, GAtServerResult result)
@@ -380,7 +381,7 @@ static void new_bytes(GAtServer *p)
/* We're overflowing the buffer, shutdown the socket */
if (p->read_buf && ring_buffer_avail(p->read_buf) == 0)
- g_source_remove(p->server_watch);
+ g_source_remove(p->read_watch);
}
static gboolean received_data(GIOChannel *channel, GIOCondition cond,
@@ -431,17 +432,25 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
return TRUE;
}
-static void server_watcher_destroy_notify(GAtServer *server)
+static void g_at_server_cleanup(GAtServer *server)
{
- server->server_watch = 0;
-
+ /* Cleanup all received data */
ring_buffer_free(server->read_buf);
server->read_buf = NULL;
server->channel = NULL;
+}
+
+static void read_watcher_destroy_notify(GAtServer *server)
+{
+ g_at_server_cleanup(server);
+ server->read_watch = 0;
if (server->user_disconnect)
server->user_disconnect(server->user_disconnect_data);
+
+ if (server->destroyed)
+ g_free(server);
}
static void v250_settings_create(struct v250_settings *v250)
@@ -480,10 +489,10 @@ GAtServer *g_at_server_new(GIOChannel *io)
if (!g_at_util_setup_io(server->channel, G_IO_FLAG_NONBLOCK))
goto error;
- server->server_watch = g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+ server->read_watch = g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
received_data, server,
- (GDestroyNotify)server_watcher_destroy_notify);
+ (GDestroyNotify)read_watcher_destroy_notify);
return server;
@@ -520,6 +529,16 @@ void g_at_server_unref(GAtServer *server)
return;
g_at_server_shutdown(server);
+
+ /* glib delays the destruction of the watcher until it exits, this
+ * means we can't free the data just yet, even though we've been
+ * destroyed already. We have to wait until the read_watcher
+ * destroy function gets called
+ */
+ if (server->read_watch != 0)
+ server->destroyed = TRUE;
+ else
+ g_free(server);
}
gboolean g_at_server_shutdown(GAtServer *server)
@@ -531,13 +550,8 @@ gboolean g_at_server_shutdown(GAtServer *server)
server->user_disconnect = NULL;
server->user_disconnect_data = NULL;
- if (server->server_watch) {
- g_source_remove(server->server_watch);
- server->server_watch = 0;
- }
-
- g_free(server);
- server = NULL;
+ if (server->read_watch)
+ g_source_remove(server->read_watch);
return TRUE;
}
--
1.6.6.1
11 years
[PATCH 1/3] Do not trigger user disconnect at g_at_shutdown
by Zhenhua Zhang
Similar to gatchat, introduce read_watcher_destroy_notify and do
not trigger user disconnect at g_at_shutdown. Delay destroy of
gatserver until read_watcher is destroyed.
---
gatchat/gatserver.c | 44 ++++++++++++++++++++++++++++++--------------
1 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
index d131b0c..bf7e847 100644
--- a/gatchat/gatserver.c
+++ b/gatchat/gatserver.c
@@ -89,7 +89,7 @@ struct _GAtServer {
gint ref_count; /* Ref count */
struct v250_settings v250; /* V.250 command setting */
GIOChannel *channel; /* Server IO */
- int server_watch; /* Watch for server IO */
+ guint read_watch; /* GSource read id, 0 if none */
guint read_so_far; /* Number of bytes processed */
GAtDisconnectFunc user_disconnect; /* User disconnect func */
gpointer user_disconnect_data; /* User disconnect data */
@@ -98,6 +98,7 @@ struct _GAtServer {
struct ring_buffer *read_buf; /* Current read buffer */
guint max_read_attempts; /* Max reads per select */
enum ParserState parser_state;
+ gboolean destroyed; /* Re-entrancy guard */
};
static void g_at_server_send_result(GAtServer *server, GAtServerResult result)
@@ -380,7 +381,7 @@ static void new_bytes(GAtServer *p)
/* We're overflowing the buffer, shutdown the socket */
if (p->read_buf && ring_buffer_avail(p->read_buf) == 0)
- g_source_remove(p->server_watch);
+ g_source_remove(p->read_watch);
}
static gboolean received_data(GIOChannel *channel, GIOCondition cond,
@@ -431,17 +432,27 @@ static gboolean received_data(GIOChannel *channel, GIOCondition cond,
return TRUE;
}
-static void server_watcher_destroy_notify(GAtServer *server)
+static void g_at_server_cleanup(GAtServer *server)
{
- server->server_watch = 0;
-
+ /* Cleanup all received data */
ring_buffer_free(server->read_buf);
server->read_buf = NULL;
server->channel = NULL;
+}
+
+static void read_watcher_destroy_notify(GAtServer *server)
+{
+ g_at_server_cleanup(server);
+ server->read_watch = 0;
+
+ server->channel = NULL;
if (server->user_disconnect)
server->user_disconnect(server->user_disconnect_data);
+
+ if (server->destroyed)
+ g_free(server);
}
static void v250_settings_create(struct v250_settings *v250)
@@ -480,10 +491,10 @@ GAtServer *g_at_server_new(GIOChannel *io)
if (!g_at_util_setup_io(server->channel, G_IO_FLAG_NONBLOCK))
goto error;
- server->server_watch = g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
+ server->read_watch = g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
received_data, server,
- (GDestroyNotify)server_watcher_destroy_notify);
+ (GDestroyNotify)read_watcher_destroy_notify);
return server;
@@ -520,6 +531,16 @@ void g_at_server_unref(GAtServer *server)
return;
g_at_server_shutdown(server);
+
+ /* glib delays the destruction of the watcher until it exits, this
+ * means we can't free the data just yet, even though we've been
+ * destroyed already. We have to wait until the read_watcher
+ * destroy function gets called
+ */
+ if (server->read_watch != 0)
+ server->destroyed = TRUE;
+ else
+ g_free(server);
}
gboolean g_at_server_shutdown(GAtServer *server)
@@ -531,13 +552,8 @@ gboolean g_at_server_shutdown(GAtServer *server)
server->user_disconnect = NULL;
server->user_disconnect_data = NULL;
- if (server->server_watch) {
- g_source_remove(server->server_watch);
- server->server_watch = 0;
- }
-
- g_free(server);
- server = NULL;
+ if (server->read_watch)
+ g_source_remove(server->read_watch);
return TRUE;
}
--
1.6.6.1
11 years
[PATCH] test: shows the id of the modem beeing enabled/disabled
by João Paulo Rechi Vita
---
test/disable-modem | 1 +
test/enable-modem | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/test/disable-modem b/test/disable-modem
index 47b8531..a1611ec 100755
--- a/test/disable-modem
+++ b/test/disable-modem
@@ -13,6 +13,7 @@ else:
properties = manager.GetProperties()
path = properties["Modems"][0]
+print "Disconnecting modem %s..." % path
modem = dbus.Interface(bus.get_object('org.ofono', path),
'org.ofono.Modem')
diff --git a/test/enable-modem b/test/enable-modem
index 86362af..02dc150 100755
--- a/test/enable-modem
+++ b/test/enable-modem
@@ -13,6 +13,7 @@ else:
properties = manager.GetProperties()
path = properties["Modems"][0]
+print "Connecting modem %s..." % path
modem = dbus.Interface(bus.get_object('org.ofono', path),
'org.ofono.Modem')
--
1.6.3.3
11 years
[PATCH] Add support of Huawei EM770 modem
by Gu, Yang
Hi,
This patch is to enable Huawei EM770 modem, which is a full feature modem that supports voicecall, phonebook, call forwarding, call barring, etc.
There are two known parts of code that may have problem and need your comments.
1. Once connecting this modem to PC via USB, we can get 5 tty ports: ttyUSB0, ttyUSB1, ttyUSB2, ttyUSB3 and ttyUSB4. The correct way to talk to this modem is using ttyUSB2. I'm not sure if I handled this correctly in file udev.c.
2. When creating the modem, a global modem id will be appended to the name of it while constructing the path. This modem has name "huawei_em770", thus the path becomes things like "/huawei_em7700" or "/huawei_em7701". This looks strange. Need I change the name of this modem, or can we use some smarter way to append the modem id?
There is also one known issue for this modem: The return of "CSMS=?" from this modem is not compatible with spec. This is deemed as a modem issue, so the sms wouldn't work before this hardware issue get solved.
Comments are welcome!
Regards,
-Yang
11 years
[PATCH] Use g_dbus_emit_signal in call-barring.c
by Zhenhua Zhang
To make it consistent with call_barring_incoming_enabled_notify.
---
src/call-barring.c | 13 ++-----------
1 files changed, 2 insertions(+), 11 deletions(-)
diff --git a/src/call-barring.c b/src/call-barring.c
index 2a04b25..e72d522 100644
--- a/src/call-barring.c
+++ b/src/call-barring.c
@@ -1001,18 +1001,9 @@ static void call_barring_outgoing_enabled_notify(int idx, void *userdata)
struct ofono_call_barring *cb = userdata;
DBusConnection *conn = ofono_dbus_get_connection();
const char *path = __ofono_atom_get_path(cb->atom);
- DBusMessage *signal;
- signal = dbus_message_new_signal(path, OFONO_CALL_BARRING_INTERFACE,
- "OutgoingBarringInEffect");
-
- if (!signal) {
- ofono_error("Unable to allocate new %s.OutgoingBarringInEffect"
- " signal", OFONO_CALL_BARRING_INTERFACE);
- return;
- }
-
- g_dbus_send_message(conn, signal);
+ g_dbus_emit_signal(conn, path, OFONO_CALL_BARRING_INTERFACE,
+ "OutgoingBarringInEffect", DBUS_TYPE_INVALID);
}
int ofono_call_barring_driver_register(const struct ofono_call_barring_driver *d)
--
1.6.6.1
11 years
[PATCH, rfc] Handle network-initiated ussd requests.
by Andrzej Zaborowski
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
11 years