* [PATCH v3 3/4] ss: Use errno for ssc handling functions
2010-10-18 8:00 [PATCH v3 1/4] Add macro for general result and additional info Yang Gu
2010-10-18 8:00 ` [PATCH v3 2/4] stk: Support send ss response Yang Gu
@ 2010-10-18 8:00 ` Yang Gu
2010-10-18 8:00 ` [PATCH v3 4/4] cf: Handle send ss proactive command Yang Gu
2010-10-20 23:22 ` [PATCH v3 1/4] Add macro for general result and additional info Denis Kenzior
3 siblings, 0 replies; 6+ messages in thread
From: Yang Gu @ 2010-10-18 8:00 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 13857 bytes --]
---
src/call-barring.c | 63 ++++++++++++++----------------------------------
src/call-forwarding.c | 63 +++++++++++++++++-------------------------------
src/call-settings.c | 34 ++++++++------------------
src/ussd.c | 55 ++++++++++++++++++++++++++++--------------
4 files changed, 88 insertions(+), 127 deletions(-)
diff --git a/src/call-barring.c b/src/call-barring.c
index f89602e..04d9bab 100644
--- a/src/call-barring.c
+++ b/src/call-barring.c
@@ -359,25 +359,19 @@ static const char *cb_ss_service_to_fac(const char *svc)
return NULL;
}
-static gboolean cb_ss_control(int type, const char *sc,
+static int cb_ss_control(int type, const char *sc,
const char *sia, const char *sib,
const char *sic, const char *dn,
DBusMessage *msg, void *data)
{
struct ofono_call_barring *cb = data;
- DBusConnection *conn = ofono_dbus_get_connection();
int cls = BEARER_CLASS_DEFAULT;
const char *fac;
- DBusMessage *reply;
void *operation = NULL;
int i;
- if (__ofono_call_barring_is_busy(cb)) {
- reply = __ofono_error_busy(msg);
- g_dbus_send_message(conn, reply);
-
- return TRUE;
- }
+ if (__ofono_call_barring_is_busy(cb))
+ return -EBUSY;
DBG("Received call barring ss control request");
@@ -386,7 +380,7 @@ static gboolean cb_ss_control(int type, const char *sc,
fac = cb_ss_service_to_fac(sc);
if (!fac)
- return FALSE;
+ return -ENOENT;
cb_set_query_bounds(cb, fac, type == SS_CONTROL_TYPE_QUERY);
@@ -397,13 +391,13 @@ static gboolean cb_ss_control(int type, const char *sc,
cb->ss_req_lock = i;
if (strlen(sic) > 0)
- goto bad_format;
+ return -EINVAL;
if (strlen(dn) > 0)
- goto bad_format;
+ return -EINVAL;
if (type != SS_CONTROL_TYPE_QUERY && !is_valid_pin(sia, PIN_TYPE_NET))
- goto bad_format;
+ return -EINVAL;
switch (type) {
case SS_CONTROL_TYPE_ACTIVATION:
@@ -419,12 +413,8 @@ static gboolean cb_ss_control(int type, const char *sc,
break;
}
- if (!operation) {
- reply = __ofono_error_not_implemented(msg);
- g_dbus_send_message(conn, reply);
-
- return TRUE;
- }
+ if (!operation)
+ return -ENOSYS;
/*
* According to 27.007, AG, AC and AB only work with mode = 0
@@ -434,7 +424,7 @@ static gboolean cb_ss_control(int type, const char *sc,
if ((!strcmp(fac, "AG") || !strcmp(fac, "AC") || !strcmp(fac, "AB")) &&
(type == SS_CONTROL_TYPE_ACTIVATION ||
type == SS_CONTROL_TYPE_REGISTRATION))
- goto bad_format;
+ return -EINVAL;
if (strlen(sib) > 0) {
long service_code;
@@ -443,12 +433,12 @@ static gboolean cb_ss_control(int type, const char *sc,
service_code = strtoul(sib, &end, 10);
if (end == sib || *end != '\0')
- goto bad_format;
+ return -EINVAL;
cls = mmi_service_code_to_bearer_class(service_code);
if (cls == 0)
- goto bad_format;
+ return -EINVAL;
}
cb->ss_req_cls = cls;
@@ -473,12 +463,7 @@ static gboolean cb_ss_control(int type, const char *sc,
break;
}
- return TRUE;
-
-bad_format:
- reply = __ofono_error_invalid_format(msg);
- g_dbus_send_message(conn, reply);
- return TRUE;
+ return 0;
}
static void cb_set_passwd_callback(const struct ofono_error *error, void *data)
@@ -496,21 +481,15 @@ static void cb_set_passwd_callback(const struct ofono_error *error, void *data)
__ofono_dbus_pending_reply(&cb->pending, reply);
}
-static gboolean cb_ss_passwd(const char *sc,
+static int cb_ss_passwd(const char *sc,
const char *old, const char *new,
DBusMessage *msg, void *data)
{
struct ofono_call_barring *cb = data;
- DBusConnection *conn = ofono_dbus_get_connection();
- DBusMessage *reply;
const char *fac;
- if (__ofono_call_barring_is_busy(cb)) {
- reply = __ofono_error_busy(msg);
- g_dbus_send_message(conn, reply);
-
- return TRUE;
- }
+ if (__ofono_call_barring_is_busy(cb))
+ return -EBUSY;
DBG("Received call barring ss password change request");
@@ -522,19 +501,15 @@ static gboolean cb_ss_passwd(const char *sc,
fac = cb_ss_service_to_fac(sc);
if (!fac)
- return FALSE;
+ return -ENOENT;
if (!is_valid_pin(old, PIN_TYPE_NET) || !is_valid_pin(new, PIN_TYPE_NET))
- goto bad_format;
+ return -EINVAL;
cb->pending = dbus_message_ref(msg);
cb->driver->set_passwd(cb, fac, old, new, cb_set_passwd_callback, cb);
- return TRUE;
-bad_format:
- reply = __ofono_error_invalid_format(msg);
- g_dbus_send_message(conn, reply);
- return TRUE;
+ return 0;
}
static void cb_register_ss_controls(struct ofono_call_barring *cb)
diff --git a/src/call-forwarding.c b/src/call-forwarding.c
index 928cda1..fd05d38 100644
--- a/src/call-forwarding.c
+++ b/src/call-forwarding.c
@@ -883,30 +883,24 @@ static void cf_ss_control_callback(const struct ofono_error *error, void *data)
ss_set_query_next_cf_cond(cf);
}
-static gboolean cf_ss_control(int type, const char *sc,
+static int cf_ss_control(int type, const char *sc,
const char *sia, const char *sib,
const char *sic, const char *dn,
DBusMessage *msg, void *data)
{
struct ofono_call_forwarding *cf = data;
- DBusConnection *conn = ofono_dbus_get_connection();
int cls = BEARER_CLASS_SS_DEFAULT;
int timeout = DEFAULT_NO_REPLY_TIMEOUT;
int cf_type;
- DBusMessage *reply;
struct ofono_phone_number ph;
void *operation = NULL;
/* Before we do anything, make sure we're actually initialized */
if (!cf)
- return FALSE;
-
- if (__ofono_call_forwarding_is_busy(cf)) {
- reply = __ofono_error_busy(msg);
- g_dbus_send_message(conn, reply);
+ return -ENOENT;
- return TRUE;
- }
+ if (__ofono_call_forwarding_is_busy(cf))
+ return -EBUSY;
DBG("Received call forwarding ss control request");
@@ -926,13 +920,13 @@ static gboolean cf_ss_control(int type, const char *sc,
else if (!strcmp(sc, "004"))
cf_type = CALL_FORWARDING_TYPE_ALL_CONDITIONAL;
else
- return FALSE;
+ return -ENOENT;
if (strlen(sia) &&
- (type == SS_CONTROL_TYPE_QUERY ||
- type == SS_CONTROL_TYPE_ERASURE ||
- type == SS_CONTROL_TYPE_DEACTIVATION))
- goto error;
+ (type == SS_CONTROL_TYPE_QUERY ||
+ type == SS_CONTROL_TYPE_ERASURE ||
+ type == SS_CONTROL_TYPE_DEACTIVATION))
+ return -EINVAL;
/*
* Activation / Registration is figured context specific according to
@@ -944,8 +938,8 @@ static gboolean cf_ss_control(int type, const char *sc,
type = SS_CONTROL_TYPE_REGISTRATION;
if (type == SS_CONTROL_TYPE_REGISTRATION &&
- !valid_phone_number_format(sia))
- goto error;
+ !valid_phone_number_format(sia))
+ return -EINVAL;
if (strlen(sib) > 0) {
long service_code;
@@ -954,32 +948,32 @@ static gboolean cf_ss_control(int type, const char *sc,
service_code = strtoul(sib, &end, 10);
if (end == sib || *end != '\0')
- goto error;
+ return -EINVAL;
cls = mmi_service_code_to_bearer_class(service_code);
if (cls == 0)
- goto error;
+ return -EINVAL;
}
if (strlen(sic) > 0) {
char *end;
if (type != SS_CONTROL_TYPE_REGISTRATION)
- goto error;
+ return -EINVAL;
if (cf_type != CALL_FORWARDING_TYPE_ALL &&
cf_type != CALL_FORWARDING_TYPE_ALL_CONDITIONAL &&
cf_type != CALL_FORWARDING_TYPE_NO_REPLY)
- goto error;
+ return -EINVAL;
timeout = strtoul(sic, &end, 10);
if (end == sic || *end != '\0')
- goto error;
+ return -EINVAL;
if (timeout < 1 || timeout > 30)
- goto error;
+ return -EINVAL;
}
switch (type) {
@@ -1000,21 +994,13 @@ static gboolean cf_ss_control(int type, const char *sc,
break;
}
- if (!operation) {
- reply = __ofono_error_not_implemented(msg);
- g_dbus_send_message(conn, reply);
-
- return TRUE;
- }
+ if (!operation)
+ return -ENOSYS;
cf->ss_req = g_try_new0(struct cf_ss_request, 1);
- if (!cf->ss_req) {
- reply = __ofono_error_failed(msg);
- g_dbus_send_message(conn, reply);
-
- return TRUE;
- }
+ if (!cf->ss_req)
+ return -ENOMEM;
cf->ss_req->ss_type = type;
cf->ss_req->cf_type = cf_type;
@@ -1070,12 +1056,7 @@ static gboolean cf_ss_control(int type, const char *sc,
break;
}
- return TRUE;
-
-error:
- reply = __ofono_error_invalid_format(msg);
- g_dbus_send_message(conn, reply);
- return TRUE;
+ return 0;
}
static void cf_register_ss_controls(struct ofono_call_forwarding *cf)
diff --git a/src/call-settings.c b/src/call-settings.c
index 23da47e..4f4812e 100644
--- a/src/call-settings.c
+++ b/src/call-settings.c
@@ -402,35 +402,29 @@ static void cw_ss_set_callback(const struct ofono_error *error, void *data)
cw_ss_query_callback, cs);
}
-static gboolean cw_ss_control(int type,
+static int cw_ss_control(int type,
const char *sc, const char *sia,
const char *sib, const char *sic,
const char *dn, DBusMessage *msg, void *data)
{
struct ofono_call_settings *cs = data;
- DBusConnection *conn = ofono_dbus_get_connection();
int cls = BEARER_CLASS_SS_DEFAULT;
- DBusMessage *reply;
if (!cs)
- return FALSE;
+ return -ENOENT;
if (strcmp(sc, "43"))
- return FALSE;
+ return -ENOENT;
- if (__ofono_call_settings_is_busy(cs)) {
- reply = __ofono_error_busy(msg);
- goto error;
- }
+ if (__ofono_call_settings_is_busy(cs))
+ return -EBUSY;
if (strlen(sib) || strlen(sib) || strlen(dn))
- goto bad_format;
+ return -EINVAL;
if ((type == SS_CONTROL_TYPE_QUERY && !cs->driver->cw_query) ||
- (type != SS_CONTROL_TYPE_QUERY && !cs->driver->cw_set)) {
- reply = __ofono_error_not_implemented(msg);
- goto error;
- }
+ (type != SS_CONTROL_TYPE_QUERY && !cs->driver->cw_set))
+ return -ENOSYS;
if (strlen(sia) > 0) {
long service_code;
@@ -439,11 +433,11 @@ static gboolean cw_ss_control(int type,
service_code = strtoul(sia, &end, 10);
if (end == sia || *end != '\0')
- goto bad_format;
+ return -EINVAL;
cls = mmi_service_code_to_bearer_class(service_code);
if (cls == 0)
- goto bad_format;
+ return -EINVAL;
}
cs->ss_req_cls = cls;
@@ -478,13 +472,7 @@ static gboolean cw_ss_control(int type,
break;
}
- return TRUE;
-
-bad_format:
- reply = __ofono_error_invalid_format(msg);
-error:
- g_dbus_send_message(conn, reply);
- return TRUE;
+ return 0;
}
static void generate_ss_query_reply(struct ofono_call_settings *cs,
diff --git a/src/ussd.c b/src/ussd.c
index 59e0a49..c0b7af8 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -205,32 +205,29 @@ static gboolean recognized_passwd_change_string(struct ofono_ussd *ussd,
break;
default:
- return FALSE;
+ return -ENOENT;
}
if (strcmp(sc, "03") || strlen(dn))
- return FALSE;
+ return -ENOENT;
/* If SIC & SID don't match, then we just bail out here */
- if (strcmp(sic, sid)) {
- DBusConnection *conn = ofono_dbus_get_connection();
- DBusMessage *reply = __ofono_error_invalid_format(msg);
- g_dbus_send_message(conn, reply);
- return TRUE;
- }
+ if (strcmp(sic, sid))
+ return -EINVAL;
while ((l = g_slist_find_custom(l, sia,
ssc_entry_find_by_service)) != NULL) {
struct ssc_entry *entry = l->data;
ofono_ussd_passwd_cb_t cb = entry->cb;
+ int result = cb(sia, sib, sic, msg, entry->user);
- if (cb(sia, sib, sic, msg, entry->user))
- return TRUE;
+ if (result != -ENOENT)
+ return result;
l = l->next;
}
- return FALSE;
+ return -ENOENT;
}
static gboolean recognized_control_string(struct ofono_ussd *ussd,
@@ -240,7 +237,8 @@ static gboolean recognized_control_string(struct ofono_ussd *ussd,
char *str = g_strdup(ss_str);
char *sc, *sia, *sib, *sic, *sid, *dn;
int type;
- gboolean ret = FALSE;
+ int ret = -ENOENT;
+ int result;
DBG("parsing control string");
@@ -256,9 +254,10 @@ static gboolean recognized_control_string(struct ofono_ussd *ussd,
* because it uses a fourth SI and is thus not a valid
* control string.
*/
- if (recognized_passwd_change_string(ussd, type, sc,
- sia, sib, sic, sid, dn, msg)) {
- ret = TRUE;
+ result = recognized_passwd_change_string(ussd, type, sc,
+ sia, sib, sic, sid, dn, msg);
+ if (result != -ENOENT) {
+ ret = result;
goto out;
}
@@ -270,8 +269,11 @@ static gboolean recognized_control_string(struct ofono_ussd *ussd,
struct ssc_entry *entry = l->data;
ofono_ussd_ssc_cb_t cb = entry->cb;
- if (cb(type, sc, sia, sib, sic, dn, msg, entry->user)) {
- ret = TRUE;
+ result = cb(type, sc, sia, sib, sic, dn, msg,
+ entry->user);
+
+ if (result != -ENOENT) {
+ ret = result;
goto out;
}
@@ -552,6 +554,7 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
int dcs = 0x0f;
unsigned char buf[160];
long num_packed;
+ int result;
if (__ofono_ussd_is_busy(ussd))
return __ofono_error_busy(msg);
@@ -564,8 +567,22 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage *msg,
return __ofono_error_invalid_format(msg);
DBG("checking if this is a recognized control string");
- if (recognized_control_string(ussd, str, msg))
- return NULL;
+
+ result = recognized_control_string(ussd, str, msg);
+ if (result != -ENOENT) {
+ switch (result) {
+ case -EBUSY:
+ return __ofono_error_busy(msg);
+ case -EINVAL:
+ return __ofono_error_invalid_format(msg);
+ case -ENOSYS:
+ return __ofono_error_not_implemented(msg);
+ case -ENOMEM:
+ return __ofono_error_failed(msg);
+ default:
+ return NULL;
+ }
+ }
vca = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_VOICECALL);
--
1.7.2.3
^ permalink raw reply related [flat|nested] 6+ messages in thread* [PATCH v3 4/4] cf: Handle send ss proactive command
2010-10-18 8:00 [PATCH v3 1/4] Add macro for general result and additional info Yang Gu
2010-10-18 8:00 ` [PATCH v3 2/4] stk: Support send ss response Yang Gu
2010-10-18 8:00 ` [PATCH v3 3/4] ss: Use errno for ssc handling functions Yang Gu
@ 2010-10-18 8:00 ` Yang Gu
2010-10-20 23:22 ` [PATCH v3 1/4] Add macro for general result and additional info Denis Kenzior
3 siblings, 0 replies; 6+ messages in thread
From: Yang Gu @ 2010-10-18 8:00 UTC (permalink / raw)
To: ofono
[-- Attachment #1: Type: text/plain, Size: 22986 bytes --]
---
src/call-forwarding.c | 262 +++++++++++++++++++++++++++++++++++++++++++++---
src/ofono.h | 28 +++++
src/stk.c | 130 ++++++++++++++++++++++++
src/ussd.c | 145 +++++++++++++++++++++++++++
4 files changed, 548 insertions(+), 17 deletions(-)
diff --git a/src/call-forwarding.c b/src/call-forwarding.c
index fd05d38..9384bff 100644
--- a/src/call-forwarding.c
+++ b/src/call-forwarding.c
@@ -55,11 +55,14 @@ struct ofono_call_forwarding {
GSList *cf_conditions[4];
int flags;
DBusMessage *pending;
+ struct ofono_ss_request *req;
int query_next;
int query_end;
struct cf_ss_request *ss_req;
struct ofono_ussd *ussd;
+ struct ofono_stk *stk;
unsigned int ussd_watch;
+ unsigned int stk_watch;
const struct ofono_call_forwarding_driver *driver;
void *driver_data;
struct ofono_atom *atom;
@@ -68,6 +71,7 @@ struct ofono_call_forwarding {
static void get_query_next_cf_cond(struct ofono_call_forwarding *cf);
static void set_query_next_cf_cond(struct ofono_call_forwarding *cf);
static void ss_set_query_next_cf_cond(struct ofono_call_forwarding *cf);
+static void ss_set_query_next_cf_cond_stk(struct ofono_call_forwarding *cf);
static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf);
struct cf_ss_request {
@@ -77,6 +81,27 @@ struct cf_ss_request {
GSList *cf_list[4];
};
+static void request_finish_stk(struct ofono_call_forwarding *cf,
+ const struct ofono_error *error)
+{
+ struct ofono_ss_request *req = cf->req;
+
+ if (req && req->cb)
+ req->cb(error, req->user_data);
+
+ cf->req = NULL;
+}
+
+static void request_cancel_stk(void *ss)
+{
+ struct ofono_call_forwarding *cf = ss;
+
+ if (!cf->req || !cf->req->cb)
+ return;
+
+ cf->req = NULL;
+}
+
static gint cf_condition_compare(gconstpointer a, gconstpointer b)
{
const struct ofono_call_forwarding_condition *ca = a;
@@ -860,12 +885,52 @@ static void ss_set_query_cf_callback(const struct ofono_error *error, int total,
}
}
+static void ss_set_query_cf_cb_stk(const struct ofono_error *error, int total,
+ const struct ofono_call_forwarding_condition *list,
+ void *data)
+{
+ struct ofono_call_forwarding *cf = data;
+ GSList *l;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ ofono_error("Setting succeeded, but query failed");
+ cf->flags &= ~CALL_FORWARDING_FLAG_CACHED;
+ request_finish_stk(cf, error);
+ return;
+ }
+
+ l = cf_cond_list_create(total, list);
+ DBG("%s conditions:", cf_type_lut[cf->query_next]);
+ cf_cond_list_print(l);
+
+ cf->ss_req->cf_list[cf->query_next] = l;
+
+ if (cf->query_next == cf->query_end) {
+ request_finish_stk(cf, error);
+ g_free(cf->ss_req);
+ cf->ss_req = NULL;
+ }
+
+ set_new_cond_list(cf, cf->query_next, l);
+
+ if (cf->query_next != cf->query_end) {
+ cf->query_next++;
+ ss_set_query_next_cf_cond_stk(cf);
+ }
+}
+
static void ss_set_query_next_cf_cond(struct ofono_call_forwarding *cf)
{
cf->driver->query(cf, cf->query_next, BEARER_CLASS_DEFAULT,
ss_set_query_cf_callback, cf);
}
+static void ss_set_query_next_cf_cond_stk(struct ofono_call_forwarding *cf)
+{
+ cf->driver->query(cf, cf->query_next, BEARER_CLASS_DEFAULT,
+ ss_set_query_cf_cb_stk, cf);
+}
+
static void cf_ss_control_callback(const struct ofono_error *error, void *data)
{
struct ofono_call_forwarding *cf = data;
@@ -883,16 +948,31 @@ static void cf_ss_control_callback(const struct ofono_error *error, void *data)
ss_set_query_next_cf_cond(cf);
}
-static int cf_ss_control(int type, const char *sc,
- const char *sia, const char *sib,
- const char *sic, const char *dn,
- DBusMessage *msg, void *data)
+static void cf_ss_control_cb_stk(const struct ofono_error *error, void *data)
{
struct ofono_call_forwarding *cf = data;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ DBG("Error occurred during cf ss control set/erasure");
+
+ request_finish_stk(cf, error);
+
+ g_free(cf->ss_req);
+ cf->ss_req = NULL;
+ return;
+ }
+
+ ss_set_query_next_cf_cond_stk(cf);
+}
+
+static int parse_ss_control(struct ofono_call_forwarding *cf, int type,
+ const char *sc, const char *sia,
+ const char *sib, const char *sic,
+ const char *dn)
+{
int cls = BEARER_CLASS_SS_DEFAULT;
int timeout = DEFAULT_NO_REPLY_TIMEOUT;
int cf_type;
- struct ofono_phone_number ph;
void *operation = NULL;
/* Before we do anything, make sure we're actually initialized */
@@ -1004,9 +1084,18 @@ static int cf_ss_control(int type, const char *sc,
cf->ss_req->ss_type = type;
cf->ss_req->cf_type = cf_type;
- cf->ss_req->cls = cls;
- cf->pending = dbus_message_ref(msg);
+ /*
+ * Some modems don't understand all classes very well, particularly
+ * the older models. So if the bearer class is the default, we
+ * just use the more commonly understood value of 7 since BEARER_SMS
+ * is not applicable to CallForwarding conditions according to 22.004
+ * Annex A
+ */
+ if (cls == BEARER_CLASS_SS_DEFAULT)
+ cls = BEARER_CLASS_DEFAULT;
+
+ cf->ss_req->cls = cls;
switch (cf->ss_req->cf_type) {
case CALL_FORWARDING_TYPE_ALL:
@@ -1023,15 +1112,34 @@ static int cf_ss_control(int type, const char *sc,
break;
}
- /*
- * Some modems don't understand all classes very well, particularly
- * the older models. So if the bearer class is the default, we
- * just use the more commonly understood value of 7 since BEARER_SMS
- * is not applicable to CallForwarding conditions according to 22.004
- * Annex A
- */
- if (cls == BEARER_CLASS_SS_DEFAULT)
- cls = BEARER_CLASS_DEFAULT;
+ return 0;
+}
+
+static int cf_ss_control(int type, const char *sc,
+ const char *sia, const char *sib,
+ const char *sic, const char *dn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_call_forwarding *cf = data;
+ int ret;
+ char *end;
+ int timeout;
+ int cls;
+ int cf_type;
+ struct ofono_phone_number ph;
+
+ ret = parse_ss_control(cf, type, sc, sia, sib, sic, dn);
+ if (ret != 0)
+ return ret;
+
+ cls = cf->ss_req->cls;
+ cf_type = cf->ss_req->cf_type;
+
+ timeout = DEFAULT_NO_REPLY_TIMEOUT;
+ if (strlen(sic) > 0)
+ timeout = strtoul(sic, &end, 10);
+
+ cf->pending = dbus_message_ref(msg);
switch (cf->ss_req->ss_type) {
case SS_CONTROL_TYPE_REGISTRATION:
@@ -1059,6 +1167,60 @@ static int cf_ss_control(int type, const char *sc,
return 0;
}
+static int cf_ss_control_stk(int type, const char *sc,
+ const char *sia, const char *sib,
+ const char *sic, const char *dn,
+ struct ofono_ss_request *req, void *data)
+{
+ struct ofono_call_forwarding *cf = data;
+ int ret;
+ char *end;
+ int timeout;
+ int cls;
+ int cf_type;
+ struct ofono_phone_number ph;
+
+ ret = parse_ss_control(cf, type, sc, sia, sib, sic, dn);
+ if (ret != 0)
+ return ret;
+
+ cls = cf->ss_req->cls;
+ cf_type = cf->ss_req->cf_type;
+
+ timeout = DEFAULT_NO_REPLY_TIMEOUT;
+ if (strlen(sic) > 0)
+ timeout = strtoul(sic, &end, 10);
+
+ cf->req = req;
+ cf->req->cancel = request_cancel_stk;
+ cf->req->ss = cf;
+
+ switch (cf->ss_req->ss_type) {
+ case SS_CONTROL_TYPE_REGISTRATION:
+ string_to_phone_number(sia, &ph);
+ cf->driver->registration(cf, cf_type, cls, &ph, timeout,
+ cf_ss_control_cb_stk, cf);
+ break;
+ case SS_CONTROL_TYPE_ACTIVATION:
+ cf->driver->activation(cf, cf_type, cls, cf_ss_control_cb_stk,
+ cf);
+ break;
+ case SS_CONTROL_TYPE_DEACTIVATION:
+ cf->driver->deactivation(cf, cf_type, cls,
+ cf_ss_control_cb_stk, cf);
+ break;
+ case SS_CONTROL_TYPE_ERASURE:
+ cf->driver->erasure(cf, cf_type, cls, cf_ss_control_cb_stk,
+ cf);
+ break;
+ case SS_CONTROL_TYPE_QUERY:
+ ss_set_query_next_cf_cond_stk(cf);
+ break;
+ }
+
+ return 0;
+}
+
static void cf_register_ss_controls(struct ofono_call_forwarding *cf)
{
__ofono_ussd_ssc_register(cf->ussd, "21", cf_ss_control, cf, NULL);
@@ -1070,6 +1232,23 @@ static void cf_register_ss_controls(struct ofono_call_forwarding *cf)
__ofono_ussd_ssc_register(cf->ussd, "004", cf_ss_control, cf, NULL);
}
+static void cf_register_ss_controls_stk(struct ofono_call_forwarding *cf)
+{
+ __ofono_ussd_ssc_register_stk(cf->ussd, "21",
+ cf_ss_control_stk, cf, NULL);
+ __ofono_ussd_ssc_register_stk(cf->ussd, "67",
+ cf_ss_control_stk, cf, NULL);
+ __ofono_ussd_ssc_register_stk(cf->ussd, "61",
+ cf_ss_control_stk, cf, NULL);
+ __ofono_ussd_ssc_register_stk(cf->ussd, "62",
+ cf_ss_control_stk, cf, NULL);
+
+ __ofono_ussd_ssc_register_stk(cf->ussd, "002",
+ cf_ss_control_stk, cf, NULL);
+ __ofono_ussd_ssc_register_stk(cf->ussd, "004",
+ cf_ss_control_stk, cf, NULL);
+}
+
static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf)
{
__ofono_ussd_ssc_unregister(cf->ussd, "21");
@@ -1081,9 +1260,26 @@ static void cf_unregister_ss_controls(struct ofono_call_forwarding *cf)
__ofono_ussd_ssc_unregister(cf->ussd, "004");
}
+static void cf_unregister_ss_controls_stk(struct ofono_call_forwarding *cf)
+{
+ __ofono_ussd_ssc_unregister_stk(cf->ussd, "21");
+ __ofono_ussd_ssc_unregister_stk(cf->ussd, "67");
+ __ofono_ussd_ssc_unregister_stk(cf->ussd, "61");
+ __ofono_ussd_ssc_unregister_stk(cf->ussd, "62");
+
+ __ofono_ussd_ssc_unregister_stk(cf->ussd, "002");
+ __ofono_ussd_ssc_unregister_stk(cf->ussd, "004");
+}
+
gboolean __ofono_call_forwarding_is_busy(struct ofono_call_forwarding *cf)
{
- return cf->pending ? TRUE : FALSE;
+ if (!cf)
+ return FALSE;
+
+ if (cf->pending || cf->req)
+ return TRUE;
+
+ return FALSE;
}
int ofono_call_forwarding_driver_register(const struct ofono_call_forwarding_driver *d)
@@ -1121,6 +1317,12 @@ static void call_forwarding_unregister(struct ofono_atom *atom)
if (cf->ussd_watch)
__ofono_modem_remove_atom_watch(modem, cf->ussd_watch);
+
+ if (cf->stk)
+ cf_unregister_ss_controls_stk(cf);
+
+ if (cf->stk_watch)
+ __ofono_modem_remove_atom_watch(modem, cf->stk_watch);
}
static void call_forwarding_remove(struct ofono_atom *atom)
@@ -1175,10 +1377,26 @@ struct ofono_call_forwarding *ofono_call_forwarding_create(struct ofono_modem *m
return cf;
}
+static void stk_watch(struct ofono_atom *atom,
+ enum ofono_atom_watch_condition cond, void *data)
+{
+ struct ofono_call_forwarding *cf = data;
+
+ if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
+ cf->stk = NULL;
+ return;
+ }
+
+ cf->stk = __ofono_atom_get_data(atom);
+ cf_register_ss_controls_stk(cf);
+}
+
static void ussd_watch(struct ofono_atom *atom,
enum ofono_atom_watch_condition cond, void *data)
{
struct ofono_call_forwarding *cf = data;
+ struct ofono_atom *stk_atom;
+ struct ofono_modem *modem = __ofono_atom_get_modem(cf->atom);
if (cond == OFONO_ATOM_WATCH_CONDITION_UNREGISTERED) {
cf->ussd = NULL;
@@ -1187,6 +1405,16 @@ static void ussd_watch(struct ofono_atom *atom,
cf->ussd = __ofono_atom_get_data(atom);
cf_register_ss_controls(cf);
+
+ cf->stk_watch = __ofono_modem_add_atom_watch(modem,
+ OFONO_ATOM_TYPE_STK,
+ stk_watch, cf, NULL);
+
+ stk_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_STK);
+
+ if (stk_atom && __ofono_atom_get_registered(stk_atom))
+ stk_watch(stk_atom, OFONO_ATOM_WATCH_CONDITION_REGISTERED,
+ cf);
}
void ofono_call_forwarding_register(struct ofono_call_forwarding *cf)
diff --git a/src/ofono.h b/src/ofono.h
index 78e6be1..7ea6abc 100644
--- a/src/ofono.h
+++ b/src/ofono.h
@@ -298,11 +298,35 @@ typedef gboolean (*ofono_ussd_passwd_cb_t)(const char *sc,
typedef void (*ofono_ussd_request_cb_t)(int error, int dcs,
const unsigned char *pdu, int len,
void *data);
+typedef void (*ofono_ss_request_cb_t)(const struct ofono_error *error,
+ void *data);
+typedef void (*ofono_ss_request_cancel_t)(void *ss);
+
+struct ofono_ss_request {
+ ofono_ss_request_cb_t cb;
+ void *user_data;
+ ofono_ss_request_cancel_t cancel;
+ void *ss;
+};
+
+typedef gboolean (*ofono_ussd_ssc_cb_stk_t)(int type, const char *sc,
+ const char *sia, const char *sib,
+ const char *sic, const char *dn,
+ struct ofono_ss_request *req,
+ void *data);
+typedef gboolean (*ofono_ussd_passwd_cb_stk_t)(const char *sc,
+ const char *old, const char *new,
+ struct ofono_ss_request *req,
+ void *data);
gboolean __ofono_ussd_ssc_register(struct ofono_ussd *ussd, const char *sc,
ofono_ussd_ssc_cb_t cb, void *data,
ofono_destroy_func destroy);
+gboolean __ofono_ussd_ssc_register_stk(struct ofono_ussd *ussd, const char *sc,
+ ofono_ussd_ssc_cb_stk_t cb, void *data,
+ ofono_destroy_func destroy);
void __ofono_ussd_ssc_unregister(struct ofono_ussd *ussd, const char *sc);
+void __ofono_ussd_ssc_unregister_stk(struct ofono_ussd *ussd, const char *sc);
gboolean __ofono_ussd_passwd_register(struct ofono_ussd *ussd, const char *sc,
ofono_ussd_passwd_cb_t cb, void *data,
@@ -315,6 +339,10 @@ int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs,
ofono_ussd_request_cb_t cb, void *user_data);
void __ofono_ussd_initiate_cancel(struct ofono_ussd *ussd);
+int __ofono_ussd_recognized_control_string_stk(struct ofono_ussd *ussd,
+ const char *ss_str,
+ struct ofono_ss_request *req);
+
#include <ofono/netreg.h>
typedef void (*ofono_netreg_status_notify_cb_t)(int status, int lac, int ci,
diff --git a/src/stk.c b/src/stk.c
index 60b308b..a152f19 100644
--- a/src/stk.c
+++ b/src/stk.c
@@ -74,6 +74,7 @@ struct ofono_stk {
char *idle_mode_text;
struct stk_icon_id idle_mode_icon;
struct timeval get_inkey_start_ts;
+ struct ofono_ss_request *ss_req;
};
struct envelope_op {
@@ -674,6 +675,13 @@ static GDBusSignalTable stk_signals[] = {
{ }
};
+static gboolean set_result_type(struct stk_response *rsp,
+ enum stk_result_type type)
+{
+ rsp->result.type = type;
+ return TRUE;
+}
+
static gboolean handle_command_more_time(const struct stk_command *cmd,
struct stk_response *rsp,
struct ofono_stk *stk)
@@ -759,6 +767,123 @@ static gboolean handle_command_send_sms(const struct stk_command *cmd,
return FALSE;
}
+static void send_ss_cancel(struct ofono_stk *stk)
+{
+ if (!stk->ss_req || !stk->ss_req->cancel)
+ return;
+
+ stk->ss_req->cancel(stk->ss_req->ss);
+
+ g_free(stk->ss_req);
+ stk->ss_req = NULL;
+
+ if (stk->pending_cmd->send_ss.alpha_id &&
+ stk->pending_cmd->send_ss.alpha_id[0])
+ stk_alpha_id_unset(stk);
+}
+
+static void send_ss_cb(const struct ofono_error *error, void *data)
+{
+ struct ofono_stk *stk = data;
+ static struct ofono_error oe = { .type = OFONO_ERROR_TYPE_FAILURE };
+ struct stk_response rsp;
+ unsigned char addnl;
+
+ if (stk->pending_cmd->send_ss.alpha_id &&
+ stk->pending_cmd->send_ss.alpha_id[0])
+ stk_alpha_id_unset(stk);
+
+ memset(&rsp, 0, sizeof(rsp));
+
+ switch (error->type) {
+ case OFONO_ERROR_TYPE_NO_ERROR:
+ rsp.result.type = STK_RESULT_TYPE_SUCCESS;
+ break;
+ default:
+ DBG("Send ss finishes with error type: %d", error->type);
+ rsp.result.type = STK_RESULT_TYPE_SS_RETURN_ERROR;
+ addnl = STK_RESULT_ADDNL_SS_PB_NO_SPECIFIC_CAUSE;
+ rsp.result.additional = &addnl;
+ rsp.result.additional_len = 1;
+ break;
+ }
+
+ g_free(stk->ss_req);
+ stk->ss_req = NULL;
+
+ if (stk_respond(stk, &rsp, stk_command_cb))
+ stk_command_cb(&oe, stk);
+}
+
+static gboolean handle_command_send_ss(const struct stk_command *cmd,
+ struct stk_response *rsp,
+ struct ofono_stk *stk)
+{
+ struct ofono_modem *modem = __ofono_atom_get_modem(stk->atom);
+ static unsigned char busy_on_ss_result[] = {
+ STK_RESULT_ADDNL_ME_PB_SS_BUSY };
+ static unsigned char busy_on_ussd_result[] = {
+ STK_RESULT_ADDNL_ME_PB_USSD_BUSY };
+ char *str = cmd->send_ss.ss.ss;
+ struct ofono_atom *ussd_atom;
+ struct ofono_ussd *ussd;
+ int result;
+ struct ofono_ss_request *req;
+
+ ussd_atom = __ofono_modem_find_atom(modem, OFONO_ATOM_TYPE_USSD);
+
+ if (!ussd_atom || !__ofono_atom_get_registered(ussd_atom))
+ return set_result_type(rsp, STK_RESULT_TYPE_NOT_CAPABLE);
+
+ ussd = __ofono_atom_get_data(ussd_atom);
+
+ if (__ofono_ussd_is_busy(ussd)) {
+ rsp->result.type = STK_RESULT_TYPE_TERMINAL_BUSY;
+ rsp->result.additional_len = sizeof(busy_on_ussd_result);
+ rsp->result.additional = busy_on_ussd_result;
+ return TRUE;
+ }
+
+ if (strlen(str) == 0)
+ return set_result_type(rsp,
+ STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD);
+
+ req = g_try_new0(struct ofono_ss_request, 1);
+ req->cb = send_ss_cb;
+ req->user_data = stk;
+
+ result = __ofono_ussd_recognized_control_string_stk(ussd, str, req);
+
+ if (result != 0) {
+ DBG("Failed to send ss with result: %d", result);
+ g_free(req);
+ }
+
+ switch (result) {
+ case -EBUSY:
+ rsp->result.type = STK_RESULT_TYPE_TERMINAL_BUSY;
+ rsp->result.additional_len = sizeof(busy_on_ss_result);
+ rsp->result.additional = busy_on_ss_result;
+ return TRUE;
+ case -ENOSYS:
+ case -ENOMEM:
+ return set_result_type(rsp, STK_RESULT_TYPE_NOT_CAPABLE);
+ case 0:
+ stk->ss_req = req;
+ stk->cancel_cmd = send_ss_cancel;
+
+ if (cmd->send_ss.alpha_id && cmd->send_ss.alpha_id[0])
+ stk_alpha_id_set(stk, cmd->send_ss.alpha_id,
+ &cmd->send_ss.icon_id);
+
+ return FALSE;
+ case -EINVAL:
+ default:
+ return set_result_type(rsp,
+ STK_RESULT_TYPE_COMMAND_NOT_UNDERSTOOD);
+ }
+}
+
static gboolean handle_command_set_idle_text(const struct stk_command *cmd,
struct stk_response *rsp,
struct ofono_stk *stk)
@@ -1958,6 +2083,11 @@ void ofono_stk_proactive_command_notify(struct ofono_stk *stk,
&rsp, stk);
break;
+ case STK_COMMAND_TYPE_SEND_SS:
+ respond = handle_command_send_ss(stk->pending_cmd,
+ &rsp, stk);
+ break;
+
case STK_COMMAND_TYPE_SETUP_IDLE_MODE_TEXT:
respond = handle_command_set_idle_text(stk->pending_cmd,
&rsp, stk);
diff --git a/src/ussd.c b/src/ussd.c
index c0b7af8..6d16201 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -60,7 +60,9 @@ struct ofono_ussd {
DBusMessage *cancel;
int flags;
GSList *ss_control_list;
+ GSList *ss_control_list_stk;
GSList *ss_passwd_list;
+ GSList *ss_passwd_list_stk;
const struct ofono_ussd_driver *driver;
void *driver_data;
struct ofono_atom *atom;
@@ -138,6 +140,26 @@ gboolean __ofono_ussd_ssc_register(struct ofono_ussd *ussd, const char *sc,
return TRUE;
}
+gboolean __ofono_ussd_ssc_register_stk(struct ofono_ussd *ussd, const char *sc,
+ ofono_ussd_ssc_cb_stk_t cb, void *data,
+ ofono_destroy_func destroy)
+{
+ struct ssc_entry *entry;
+
+ if (!ussd)
+ return FALSE;
+
+ entry = ssc_entry_create(sc, cb, data, destroy);
+
+ if (!entry)
+ return FALSE;
+
+ ussd->ss_control_list_stk =
+ g_slist_prepend(ussd->ss_control_list_stk, entry);
+
+ return TRUE;
+}
+
void __ofono_ussd_ssc_unregister(struct ofono_ussd *ussd, const char *sc)
{
GSList *l;
@@ -155,6 +177,24 @@ void __ofono_ussd_ssc_unregister(struct ofono_ussd *ussd, const char *sc)
ussd->ss_control_list = g_slist_remove(ussd->ss_control_list, l->data);
}
+void __ofono_ussd_ssc_unregister_stk(struct ofono_ussd *ussd, const char *sc)
+{
+ GSList *l;
+
+ if (!ussd)
+ return;
+
+ l = g_slist_find_custom(ussd->ss_control_list_stk, sc,
+ ssc_entry_find_by_service);
+
+ if (!l)
+ return;
+
+ ssc_entry_destroy(l->data);
+ ussd->ss_control_list_stk =
+ g_slist_remove(ussd->ss_control_list_stk, l->data);
+}
+
gboolean __ofono_ussd_passwd_register(struct ofono_ussd *ussd, const char *sc,
ofono_ussd_passwd_cb_t cb, void *data,
ofono_destroy_func destroy)
@@ -230,6 +270,45 @@ static gboolean recognized_passwd_change_string(struct ofono_ussd *ussd,
return -ENOENT;
}
+static int recognized_passwd_change_string_stk(struct ofono_ussd *ussd,
+ int type, char *sc, char *sia,
+ char *sib, char *sic,
+ char *sid, char *dn,
+ struct ofono_ss_request *req)
+{
+ GSList *l = ussd->ss_passwd_list;
+
+ switch (type) {
+ case SS_CONTROL_TYPE_ACTIVATION:
+ case SS_CONTROL_TYPE_REGISTRATION:
+ break;
+
+ default:
+ return -ENOENT;
+ }
+
+ if (strcmp(sc, "03") || strlen(dn))
+ return -ENOENT;
+
+ /* If SIC & SID don't match, then we just bail out here */
+ if (strcmp(sic, sid))
+ return EINVAL;
+
+ while ((l = g_slist_find_custom(l, sia,
+ ssc_entry_find_by_service)) != NULL) {
+ struct ssc_entry *entry = l->data;
+ ofono_ussd_passwd_cb_stk_t cb = entry->cb;
+ int result = cb(sia, sib, sic, req, entry->user);
+
+ if (result != -ENOENT)
+ return result;
+
+ l = l->next;
+ }
+
+ return -ENOENT;
+}
+
static gboolean recognized_control_string(struct ofono_ussd *ussd,
const char *ss_str,
DBusMessage *msg)
@@ -298,6 +377,72 @@ out:
return ret;
}
+int __ofono_ussd_recognized_control_string_stk(struct ofono_ussd *ussd,
+ const char *ss_str, struct ofono_ss_request *req)
+{
+ char *str = g_strdup(ss_str);
+ char *sc, *sia, *sib, *sic, *sid, *dn;
+ int type;
+ int ret = -ENOENT;
+ int result;
+
+ DBG("parsing control string");
+
+ if (parse_ss_control_string(str, &type, &sc,
+ &sia, &sib, &sic, &sid, &dn)) {
+ GSList *l = ussd->ss_control_list_stk;
+
+ DBG("Got parse result: %d, %s, %s, %s, %s, %s, %s",
+ type, sc, sia, sib, sic, sid, dn);
+
+ /* A password change string needs to be treated separately
+ * because it uses a fourth SI and is thus not a valid
+ * control string. */
+ result = recognized_passwd_change_string_stk(ussd, type, sc,
+ sia, sib, sic, sid, dn, req);
+
+ if (result != -ENOENT) {
+ ret = result;
+ goto out;
+ }
+
+ if (*sid != '\0')
+ goto out;
+
+ while ((l = g_slist_find_custom(l, sc,
+ ssc_entry_find_by_service)) != NULL) {
+ struct ssc_entry *entry = l->data;
+ ofono_ussd_ssc_cb_stk_t cb = entry->cb;
+
+ result = cb(type, sc, sia, sib, sic, dn,
+ req, entry->user);
+
+ if (result != -ENOENT) {
+ ret = result;
+ goto out;
+ }
+
+ l = l->next;
+ }
+
+ }
+
+ /* TODO: Handle all strings that control voice calls */
+
+ /* TODO: Handle Multiple subscriber profile DN*59#SEND and *59#SEND
+ */
+
+ /* Note: SIM PIN/PIN2 change and unblock and IMEI presentation
+ * procedures are not handled by the daemon since they are not followed
+ * by SEND and are not valid USSD requests.
+ */
+
+out:
+ g_free(str);
+
+ return ret;
+}
+
static const char *ussd_get_state_string(struct ofono_ussd *ussd)
{
switch (ussd->state) {
--
1.7.2.3
^ permalink raw reply related [flat|nested] 6+ messages in thread