From mboxrd@z Thu Jan 1 00:00:00 1970 Content-Type: multipart/mixed; boundary="===============0899303341624804410==" MIME-Version: 1.0 From: Jeevaka Badrappan Subject: [PATCH 11/12] Internal and Driver api changes for Send USSD proactive command Date: Thu, 09 Sep 2010 05:31:55 -0700 Message-ID: <1284035516-21359-12-git-send-email-jeevaka.badrappan@elektrobit.com> In-Reply-To: <1284035516-21359-1-git-send-email-jeevaka.badrappan@elektrobit.com> List-Id: To: ofono@ofono.org --===============0899303341624804410== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable --- drivers/atmodem/ussd.c | 81 ++++++++++----------- drivers/isimodem/ussd.c | 44 ++++-------- include/types.h | 1 + include/ussd.h | 8 ++- src/ofono.h | 17 +++++ src/ussd.c | 179 ++++++++++++++++++++++++++++++++++++++++++-= ---- 6 files changed, 236 insertions(+), 94 deletions(-) diff --git a/drivers/atmodem/ussd.c b/drivers/atmodem/ussd.c index cb1515f..573417a 100644 --- a/drivers/atmodem/ussd.c +++ b/drivers/atmodem/ussd.c @@ -67,15 +67,14 @@ static void read_charset_cb(gboolean ok, GAtResult *res= ult, = static void cusd_parse(GAtResult *result, struct ofono_ussd *ussd) { + struct ussd_data *data =3D ofono_ussd_get_data(ussd); GAtResultIter iter; int status; int dcs; const char *content; - char *converted =3D NULL; - gboolean udhi; enum sms_charset charset; - gboolean compressed; - gboolean iso639; + unsigned char msg[182]; + long msg_len =3D 0; = g_at_result_iter_init(&iter, result); = @@ -89,33 +88,27 @@ static void cusd_parse(GAtResult *result, struct ofono_= ussd *ussd) goto out; = if (g_at_result_iter_next_number(&iter, &dcs)) { - if (!cbs_dcs_decode(dcs, &udhi, NULL, &charset, - &compressed, NULL, &iso639)) - goto out; - - if (udhi || compressed || iso639) + if (!cbs_dcs_decode(dcs, NULL, NULL, &charset, + NULL, NULL, NULL)) goto out; } else charset =3D SMS_CHARSET_7BIT; = - if (charset =3D=3D SMS_CHARSET_7BIT) - converted =3D convert_gsm_to_utf8((const guint8 *) content, - strlen(content), NULL, NULL, 0); - - else if (charset =3D=3D SMS_CHARSET_8BIT) { - /* TODO: Figure out what to do with 8 bit data */ - ofono_error("8-bit coded USSD response received"); - status =3D 4; /* Not supported */ - } else { + if (charset =3D=3D SMS_CHARSET_7BIT) { + if (data->charset =3D=3D AT_UTIL_CHARSET_GSM) + pack_7bit_own_buf((const guint8 *) content, = + strlen(content), 0, TRUE, + &msg_len, 0, msg); + } else if (charset =3D=3D SMS_CHARSET_8BIT) + decode_hex_own_buf(content, -1, &msg_len, 0, msg); + else { /* No other encoding is mentioned in TS27007 7.15 */ ofono_error("Unsupported USSD data coding scheme (%02x)", dcs); status =3D 4; /* Not supported */ } = out: - ofono_ussd_notify(ussd, status, converted); - - g_free(converted); + ofono_ussd_notify(ussd, status, dcs, msg, (int) msg_len); } = static void cusd_request_cb(gboolean ok, GAtResult *result, gpointer user_= data) @@ -132,45 +125,50 @@ static void cusd_request_cb(gboolean ok, GAtResult *r= esult, gpointer user_data) cusd_parse(result, ussd); } = -static void at_ussd_request(struct ofono_ussd *ussd, const char *str, +static void at_ussd_request(struct ofono_ussd *ussd, int dcs, + const unsigned char *binary_data, + int binary_data_len, ofono_ussd_cb_t cb, void *user_data) { struct ussd_data *data =3D ofono_ussd_get_data(ussd); struct cb_data *cbd =3D cb_data_new(cb, user_data); - unsigned char *converted =3D NULL; - int dcs; - int max_len; - long written; char buf[256]; + long max_chars =3D 182; + unsigned char *unpacked_buf =3D NULL; + long written; + enum sms_charset charset; = if (!cbd) goto error; = cbd->user =3D ussd; + = + if (!cbs_dcs_decode(dcs, NULL, NULL, &charset, + NULL, NULL, NULL)) + charset =3D SMS_CHARSET_7BIT; = - converted =3D convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0); - - if (!converted) - goto error; - else { - dcs =3D 15; - max_len =3D 182; - } + if (charset =3D=3D SMS_CHARSET_7BIT) { + unpacked_buf =3D unpack_7bit(binary_data, binary_data_len, 0, + TRUE, max_chars, &written, 0); = - if (written > max_len) - goto error; + if ( !unpacked_buf || written <=3D 0) + goto error; = - snprintf(buf, sizeof(buf), "AT+CUSD=3D1,\"%.*s\",%d", - (int) written, converted, dcs); + snprintf(buf, sizeof(buf), "AT+CUSD=3D1,\"%.*s\",%d", + (int) written, unpacked_buf, dcs); = - g_free(converted); - converted =3D NULL; + g_free(unpacked_buf); + unpacked_buf =3D NULL; + } else = + snprintf(buf, sizeof(buf), "AT+CUSD=3D1,\"%.*s\",%d", + binary_data_len, binary_data, dcs); = if (data->vendor =3D=3D OFONO_VENDOR_QUALCOMM_MSM) { /* Ensure that the modem is using GSM character set. It * seems it defaults to IRA and then umlauts are not * properly encoded. The modem returns some weird from - * of Latin-1, but it is not really Latin-1 either. */ + * of Latin-1, but it is not really Latin-1 either. + */ g_at_chat_send(data->chat, "AT+CSCS=3D\"GSM\"", none_prefix, NULL, NULL, NULL); } @@ -181,7 +179,6 @@ static void at_ussd_request(struct ofono_ussd *ussd, co= nst char *str, = error: g_free(cbd); - g_free(converted); = CALLBACK_WITH_FAILURE(cb, user_data); } diff --git a/drivers/isimodem/ussd.c b/drivers/isimodem/ussd.c index 330a141..6ac945b 100644 --- a/drivers/isimodem/ussd.c +++ b/drivers/isimodem/ussd.c @@ -74,7 +74,9 @@ static void ussd_parse(struct ofono_ussd *ussd, const voi= d *restrict data, { const unsigned char *msg =3D data; int status =3D OFONO_USSD_STATUS_NOT_SUPPORTED; - char *converted =3D NULL; + int msg_len =3D 0; + int dcs =3D -1; + unsigned char *coded_msg =3D NULL; = if (!msg || len < 4) goto out; @@ -84,14 +86,11 @@ static void ussd_parse(struct ofono_ussd *ussd, const v= oid *restrict data, if (msg[3] =3D=3D 0 || (size_t)(msg[3] + 4) > len) goto out; = - converted =3D ussd_decode(msg[1], msg[3], msg + 4); - - if (converted) - status =3D OFONO_USSD_STATUS_NOTIFY; - + dcs =3D msg[1]; + msg_len =3D msg[3]; + coded_msg =3D (guint8 *) msg+4; out: - ofono_ussd_notify(ussd, status, converted); - g_free(converted); + ofono_ussd_notify(ussd, status, dcs, coded_msg, msg_len); } = = @@ -129,7 +128,7 @@ error: } = static GIsiRequest *ussd_send(GIsiClient *client, - uint8_t *str, size_t len, + int dcs, uint8_t *str, size_t len, void *data, GDestroyNotify notify) { const uint8_t msg[] =3D { @@ -138,7 +137,7 @@ static GIsiRequest *ussd_send(GIsiClient *client, 0x01, /* subblock count */ SS_GSM_USSD_STRING, 4 + len + 3, /* subblock length */ - 0x0f, /* DCS */ + dcs, /* DCS */ len, /* string length */ /* USSD string goes here */ }; @@ -152,33 +151,18 @@ static GIsiRequest *ussd_send(GIsiClient *client, ussd_send_resp_cb, data, notify); } = -static void isi_request(struct ofono_ussd *ussd, const char *str, - ofono_ussd_cb_t cb, void *data) +static void isi_request(struct ofono_ussd *ussd, int dcs, + const unsigned char *binary_data, int binary_data_len, + ofono_ussd_cb_t cb, void *data) { struct ussd_data *ud =3D ofono_ussd_get_data(ussd); struct isi_cb_data *cbd =3D isi_cb_data_new(ussd, cb, data); - unsigned char buf[256]; - unsigned char *packed =3D NULL; - unsigned char *converted =3D NULL; - long num_packed; - long written; = if (!cbd) goto error; = - converted =3D convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0); - if (!converted) - goto error; - - packed =3D pack_7bit_own_buf(converted, written, 0, TRUE, - &num_packed, 0, buf); - - g_free(converted); - - if (written > SS_MAX_USSD_LENGTH) - goto error; - - if (ussd_send(ud->client, packed, num_packed, cbd, g_free)) + if (ussd_send(ud->client, dcs, (guint8 *) binary_data, + binary_data_len, cbd, g_free)) return; = error: diff --git a/include/types.h b/include/types.h index 6098cba..fbd3c6a 100644 --- a/include/types.h +++ b/include/types.h @@ -77,6 +77,7 @@ struct ofono_error { }; = #define OFONO_MAX_PHONE_NUMBER_LENGTH 20 +#define OFONO_MAX_USSD_LENGTH 160 = struct ofono_phone_number { char number[OFONO_MAX_PHONE_NUMBER_LENGTH + 1]; diff --git a/include/ussd.h b/include/ussd.h index 96e04cb..08dfc40 100644 --- a/include/ussd.h +++ b/include/ussd.h @@ -45,13 +45,15 @@ struct ofono_ussd_driver { const char *name; int (*probe)(struct ofono_ussd *ussd, unsigned int vendor, void *data); void (*remove)(struct ofono_ussd *ussd); - void (*request)(struct ofono_ussd *ussd, const char *str, - ofono_ussd_cb_t, void *data); + void (*request)(struct ofono_ussd *ussd, int dcs, + const unsigned char *binary_data, int binary_data_len, + ofono_ussd_cb_t, void *data); void (*cancel)(struct ofono_ussd *ussd, ofono_ussd_cb_t cb, void *data); }; = -void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *st= r); +void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs, + const unsigned char *data, int data_len); = int ofono_ussd_driver_register(const struct ofono_ussd_driver *d); void ofono_ussd_driver_unregister(const struct ofono_ussd_driver *d); diff --git a/src/ofono.h b/src/ofono.h index 9b8d938..bc67c73 100644 --- a/src/ofono.h +++ b/src/ofono.h @@ -244,6 +244,13 @@ gboolean __ofono_ssn_mt_watch_remove(struct ofono_ssn = *ssn, int id); = #include = +enum ofono_ussd_failure { + OFONO_USSD_FAILURE_NONE, + OFONO_USSD_FAILURE_USER_TERMINATED, + OFONO_USSD_FAILURE_RETURN_ERROR, + OFONO_USSD_FAILURE_TIMED_OUT, +}; + typedef gboolean (*ofono_ussd_ssc_cb_t)(int type, const char *sc, const char *sia, const char *sib, @@ -254,6 +261,10 @@ typedef gboolean (*ofono_ussd_passwd_cb_t)(const char = *sc, const char *old, const char *new, DBusMessage *msg, void *data); = +typedef void (*ofono_ussd_request_cb_t)(int error, int dcs, + const unsigned char *str, + int str_len, 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); @@ -264,6 +275,12 @@ gboolean __ofono_ussd_passwd_register(struct ofono_uss= d *ussd, const char *sc, ofono_destroy_func destroy); void __ofono_ussd_passwd_unregister(struct ofono_ussd *ussd, const char *s= c); = +gboolean __ofono_ussd_is_busy(struct ofono_ussd *ussd); + +int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs, + const unsigned char *binary_data, int binary_data_len, + ofono_ussd_request_cb_t cb, void *user_data); + #include = typedef void (*ofono_netreg_status_notify_cb_t)(int status, int lac, int c= i, diff --git a/src/ussd.c b/src/ussd.c index 825d560..c58bd7c 100644 --- a/src/ussd.c +++ b/src/ussd.c @@ -34,6 +34,8 @@ #include "ofono.h" = #include "common.h" +#include "smsutil.h" +#include "util.h" = #define SUPPLEMENTARY_SERVICES_INTERFACE "org.ofono.SupplementaryServices" = @@ -46,6 +48,15 @@ enum ussd_state { USSD_STATE_RESPONSE_SENT, }; = +struct ussd_request { + struct ofono_ussd *ussd; + int dcs; + unsigned char *str; + int str_len; + ofono_ussd_request_cb_t cb; + void *user_data; +}; + struct ofono_ussd { int state; DBusMessage *pending; @@ -56,6 +67,7 @@ struct ofono_ussd { const struct ofono_ussd_driver *driver; void *driver_data; struct ofono_atom *atom; + struct ussd_request *req; }; = struct ssc_entry { @@ -306,15 +318,56 @@ static void ussd_change_state(struct ofono_ussd *ussd= , int state) "State", DBUS_TYPE_STRING, &value); } = -void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char *st= r) +static void ussd_request_finish(struct ofono_ussd *ussd, int error, int dc= s, + const unsigned char *str, int str_len) +{ + struct ussd_request *req =3D ussd->req; + + if (req && req->cb) { + req->cb(error, dcs, str, str_len, req->user_data); + g_free(req->str); + g_free(req); + ussd->req =3D NULL; + } +} + +static int ussd_status_to_failure_code(int status) +{ + switch (status) { + case OFONO_USSD_STATUS_TIMED_OUT: + return OFONO_USSD_FAILURE_TIMED_OUT; + case OFONO_USSD_STATUS_NOT_SUPPORTED: + return OFONO_USSD_FAILURE_RETURN_ERROR; + } + + return OFONO_USSD_FAILURE_NONE; +} + +void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs, + const unsigned char *data, int data_len) { DBusConnection *conn =3D ofono_dbus_get_connection(); const char *ussdstr =3D "USSD"; + char *utf8_str =3D NULL; + gboolean utf8_str_valid =3D FALSE; const char sig[] =3D { DBUS_TYPE_STRING, 0 }; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter variant; = + if (ussd->req && + (status =3D=3D OFONO_USSD_STATUS_NOTIFY || + status =3D=3D OFONO_USSD_STATUS_TERMINATED || + status =3D=3D OFONO_USSD_STATUS_TIMED_OUT || + status =3D=3D OFONO_USSD_STATUS_NOT_SUPPORTED)) { + + ussd_request_finish(ussd, ussd_status_to_failure_code(status), + dcs, data, data_len); + + ussd_change_state(ussd, USSD_STATE_IDLE); + return; + } + if (status =3D=3D OFONO_USSD_STATUS_NOT_SUPPORTED) { ussd_change_state(ussd, USSD_STATE_IDLE); = @@ -334,15 +387,21 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int s= tatus, const char *str) reply =3D __ofono_error_timed_out(ussd->pending); goto out; } + = + if (data && data_len > 0) + utf8_str =3D ussd_decode(dcs, data_len, data); + + if (!utf8_str) { + utf8_str =3D ""; + status =3D OFONO_USSD_STATUS_NOTIFY; + } else + utf8_str_valid =3D TRUE; = /* TODO: Rework this in the Agent framework */ if (ussd->state =3D=3D USSD_STATE_ACTIVE) { = reply =3D dbus_message_new_method_return(ussd->pending); = - if (!str) - str =3D ""; - dbus_message_iter_init_append(reply, &iter); = dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, @@ -352,7 +411,7 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int sta= tus, const char *str) &variant); = dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING, - &str); + &utf8_str); = dbus_message_iter_close_container(&iter, &variant); = @@ -364,10 +423,7 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int st= atus, const char *str) } else if (ussd->state =3D=3D USSD_STATE_RESPONSE_SENT) { reply =3D dbus_message_new_method_return(ussd->pending); = - if (!str) - str =3D ""; - - dbus_message_append_args(reply, DBUS_TYPE_STRING, &str, + dbus_message_append_args(reply, DBUS_TYPE_STRING, &utf8_str, DBUS_TYPE_INVALID); = if (status =3D=3D OFONO_USSD_STATUS_ACTION_REQUIRED) @@ -387,20 +443,17 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int s= tatus, const char *str) signal_name =3D "NotificationReceived"; } = - if (!str) - str =3D ""; - g_dbus_emit_signal(conn, path, SUPPLEMENTARY_SERVICES_INTERFACE, signal_name, - DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID); + DBUS_TYPE_STRING, &utf8_str, DBUS_TYPE_INVALID); = ussd_change_state(ussd, new_state); - return; + goto free; } else { ofono_error("Received an unsolicited USSD but can't handle."); - DBG("USSD is: status: %d, %s", status, str); + DBG("USSD is: status: %d, %s", status, utf8_str); = - return; + goto free; } = out: @@ -408,6 +461,10 @@ out: = dbus_message_unref(ussd->pending); ussd->pending =3D NULL; + +free: + if (utf8_str_valid) + g_free(utf8_str); } = static void ussd_callback(const struct ofono_error *error, void *data) @@ -436,6 +493,12 @@ static DBusMessage *ussd_initiate(DBusConnection *conn= , DBusMessage *msg, { struct ofono_ussd *ussd =3D data; const char *str; + int dcs =3D 0x0f; + unsigned char buf[256]; + unsigned char *converted; + unsigned char *packed =3D NULL; + long num_packed; + long written; = if (ussd->pending) return __ofono_error_busy(msg); @@ -458,14 +521,27 @@ static DBusMessage *ussd_initiate(DBusConnection *con= n, DBusMessage *msg, if (!valid_ussd_string(str)) return __ofono_error_invalid_format(msg); = - DBG("OK, running USSD request"); + converted =3D convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0); + if (!converted) + return __ofono_error_invalid_format(msg); + + packed =3D pack_7bit_own_buf(converted, written, 0, TRUE, + &num_packed, 0, buf); + + g_free(converted); + + if (num_packed > OFONO_MAX_USSD_LENGTH) + return __ofono_error_invalid_format(msg); = if (!ussd->driver->request) return __ofono_error_not_implemented(msg); = + DBG("OK, running USSD request"); + ussd->pending =3D dbus_message_ref(msg); = - ussd->driver->request(ussd, str, ussd_callback, ussd); + ussd->driver->request(ussd, dcs, packed, (int) num_packed, + ussd_callback, ussd); = return NULL; } @@ -496,6 +572,12 @@ static DBusMessage *ussd_respond(DBusConnection *conn,= DBusMessage *msg, { struct ofono_ussd *ussd =3D data; const char *str; + int dcs =3D 0x0f; + unsigned char buf[256]; + unsigned char *converted; + unsigned char *packed =3D NULL; + long num_packed; + long written; = if (ussd->pending) return __ofono_error_busy(msg); @@ -510,12 +592,25 @@ static DBusMessage *ussd_respond(DBusConnection *conn= , DBusMessage *msg, if (strlen(str) =3D=3D 0) return __ofono_error_invalid_format(msg); = + converted =3D convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0); + if (!converted) + return __ofono_error_invalid_format(msg); + + packed =3D pack_7bit_own_buf(converted, written, 0, TRUE, + &num_packed, 0, buf); + + g_free(converted); + + if (num_packed > OFONO_MAX_USSD_LENGTH) + return __ofono_error_invalid_args(msg); + if (!ussd->driver->request) return __ofono_error_not_implemented(msg); = ussd->pending =3D dbus_message_ref(msg); = - ussd->driver->request(ussd, str, ussd_response_callback, ussd); + ussd->driver->request(ussd, dcs, packed, (int) num_packed, + ussd_response_callback, ussd); = return NULL; } @@ -543,6 +638,9 @@ static void ussd_cancel_callback(const struct ofono_err= or *error, void *data) reply =3D dbus_message_new_method_return(ussd->cancel); __ofono_dbus_pending_reply(&ussd->cancel, reply); = + if (ussd->req) + ussd_request_finish(ussd, -1, USSD_STATE_USER_ACTION, NULL, -1); + ussd_change_state(ussd, USSD_STATE_IDLE); } = @@ -741,3 +839,46 @@ void *ofono_ussd_get_data(struct ofono_ussd *ussd) { return ussd->driver_data; } + +static void ussd_request_callback(const struct ofono_error *error, void *d= ata) +{ + struct ofono_ussd *ussd =3D data; + + if (error->type !=3D OFONO_ERROR_TYPE_NO_ERROR) + ussd_request_finish(ussd, OFONO_USSD_FAILURE_RETURN_ERROR, -1, NULL, -1); + else + ussd_change_state(ussd,USSD_STATE_ACTIVE); +} + +gboolean __ofono_ussd_is_busy(struct ofono_ussd *ussd) +{ + if (ussd->pending || ussd->state !=3D USSD_STATE_IDLE || ussd->req) + return TRUE; + + return FALSE; +} + +int __ofono_ussd_initiate(struct ofono_ussd *ussd, int dcs, + const unsigned char *binary_data, + int binary_data_len, + ofono_ussd_request_cb_t cb, void *user_data) +{ + struct ussd_request *req; + + if (!ussd->driver->request) + return -ENOSYS; + + req =3D g_try_new0(struct ussd_request, 1); + req->dcs =3D dcs; + req->str =3D g_memdup(binary_data, binary_data_len); + req->str_len =3D binary_data_len; + req->cb =3D cb; + req->user_data =3D user_data; + + ussd->req =3D req; + + ussd->driver->request(ussd, dcs, binary_data, binary_data_len, + ussd_request_callback, ussd); + + return 0; +} -- = 1.7.0.4 --===============0899303341624804410==--