---
drivers/atmodem/ussd.c | 86 +++++++++++++++++++++++++---------------------
drivers/isimodem/ussd.c | 44 +++++++----------------
include/ussd.h | 8 +++--
src/ussd.c | 87 ++++++++++++++++++++++++++++++++++++----------
4 files changed, 133 insertions(+), 92 deletions(-)
diff --git a/drivers/atmodem/ussd.c b/drivers/atmodem/ussd.c
index 30145ad..ac99f0e 100644
--- a/drivers/atmodem/ussd.c
+++ b/drivers/atmodem/ussd.c
@@ -65,15 +65,15 @@ static void read_charset_cb(gboolean ok, GAtResult *result,
static void cusd_parse(GAtResult *result, struct ofono_ussd *ussd)
{
+ struct ussd_data *data = ofono_ussd_get_data(ussd);
GAtResultIter iter;
int status;
int dcs;
const char *content;
- char *converted = NULL;
- gboolean udhi;
enum sms_charset charset;
- gboolean compressed;
- gboolean iso639;
+ unsigned char msg[160];
+ long msg_len = 0;
+ unsigned char *msg_ptr = NULL;
g_at_result_iter_init(&iter, result);
@@ -87,33 +87,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 = SMS_CHARSET_7BIT;
- if (charset == SMS_CHARSET_7BIT)
- converted = convert_gsm_to_utf8((const guint8 *) content,
- strlen(content), NULL, NULL, 0);
-
- else if (charset == SMS_CHARSET_8BIT) {
- /* TODO: Figure out what to do with 8 bit data */
- ofono_error("8-bit coded USSD response received");
- status = 4; /* Not supported */
- } else {
+ if (charset == SMS_CHARSET_7BIT) {
+ if (data->charset == AT_UTIL_CHARSET_GSM)
+ msg_ptr = pack_7bit_own_buf((const guint8 *) content,
+ strlen(content), 0, TRUE,
+ &msg_len, 0, msg);
+ } else if (charset == SMS_CHARSET_8BIT)
+ msg_ptr = 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 = 4; /* Not supported */
}
out:
- ofono_ussd_notify(ussd, status, converted);
-
- g_free(converted);
+ ofono_ussd_notify(ussd, status, dcs, msg_ptr, msg_len);
}
static void cusd_request_cb(gboolean ok, GAtResult *result, gpointer user_data)
@@ -130,39 +124,52 @@ static void cusd_request_cb(gboolean ok, GAtResult *result, 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 *pdu, int len,
ofono_ussd_cb_t cb, void *user_data)
{
struct ussd_data *data = ofono_ussd_get_data(ussd);
struct cb_data *cbd = cb_data_new(cb, user_data);
- unsigned char *converted = NULL;
- int dcs;
- int max_len;
- long written;
char buf[256];
+ long max_chars = 182;
+ unsigned char *unpacked_buf = NULL;
+ char *converted = NULL;
+ long written;
+ enum sms_charset charset;
if (!cbd)
goto error;
cbd->user = ussd;
+
+ if (!cbs_dcs_decode(dcs, NULL, NULL, &charset,
+ NULL, NULL, NULL))
+ goto error;
- converted = convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0);
+ if (charset == SMS_CHARSET_7BIT) {
+ unpacked_buf = unpack_7bit(pdu, len, 0, TRUE, max_chars,
+ &written, 0);
- if (!converted)
- goto error;
- else {
- dcs = 15;
- max_len = 182;
- }
+ if ( !unpacked_buf || written <= 0)
+ goto error;
- if (written > max_len)
- goto error;
+ snprintf(buf, sizeof(buf), "AT+CUSD=1,\"%.*s\",%d",
+ (int) written, unpacked_buf, dcs);
+
+ g_free(unpacked_buf);
+ unpacked_buf = NULL;
+ } else {
+ converted = encode_hex(pdu, len, 0);
- snprintf(buf, sizeof(buf), "AT+CUSD=1,\"%.*s\",%d",
- (int) written, converted, dcs);
+ if (!converted)
+ goto error;
- g_free(converted);
- converted = NULL;
+ snprintf(buf, sizeof(buf), "AT+CUSD=1,\"%.*s\",%d",
+ strlen(converted), converted, dcs);
+
+ g_free(converted);
+ converted = NULL;
+ }
if (data->vendor == OFONO_VENDOR_QUALCOMM_MSM) {
/* Ensure that the modem is using GSM character set. It
@@ -179,7 +186,6 @@ static void at_ussd_request(struct ofono_ussd *ussd, const 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 void *restrict
data,
{
const unsigned char *msg = data;
int status = OFONO_USSD_STATUS_NOT_SUPPORTED;
- char *converted = NULL;
+ int msg_len = 0;
+ int dcs = -1;
+ unsigned char *coded_msg = NULL;
if (!msg || len < 4)
goto out;
@@ -84,14 +86,11 @@ static void ussd_parse(struct ofono_ussd *ussd, const void *restrict
data,
if (msg[3] == 0 || (size_t)(msg[3] + 4) > len)
goto out;
- converted = ussd_decode(msg[1], msg[3], msg + 4);
-
- if (converted)
- status = OFONO_USSD_STATUS_NOTIFY;
-
+ dcs = msg[1];
+ msg_len = msg[3];
+ coded_msg = (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[] = {
@@ -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 = ofono_ussd_get_data(ussd);
struct isi_cb_data *cbd = isi_cb_data_new(ussd, cb, data);
- unsigned char buf[256];
- unsigned char *packed = NULL;
- unsigned char *converted = NULL;
- long num_packed;
- long written;
if (!cbd)
goto error;
- converted = convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0);
- if (!converted)
- goto error;
-
- packed = 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/ussd.h b/include/ussd.h
index 96e04cb..360ef00 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 *pdu, int 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 *str);
+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/ussd.c b/src/ussd.c
index fbb07d2..a2e9e72 100644
--- a/src/ussd.c
+++ b/src/ussd.c
@@ -34,8 +34,11 @@
#include "ofono.h"
#include "common.h"
+#include "smsutil.h"
+#include "util.h"
#define SUPPLEMENTARY_SERVICES_INTERFACE "org.ofono.SupplementaryServices"
+#define MAX_USSD_LENGTH 160
static GSList *g_drivers = NULL;
@@ -317,10 +320,13 @@ 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 *str)
+void ofono_ussd_notify(struct ofono_ussd *ussd, int status, int dcs,
+ const unsigned char *data, int data_len)
{
DBusConnection *conn = ofono_dbus_get_connection();
const char *ussdstr = "USSD";
+ char *utf8_str = NULL;
+ gboolean utf8_str_valid = FALSE;
const char sig[] = { DBUS_TYPE_STRING, 0 };
DBusMessage *reply;
DBusMessageIter iter;
@@ -345,15 +351,21 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const
char *str)
reply = __ofono_error_timed_out(ussd->pending);
goto out;
}
+
+ if (data && data_len > 0)
+ utf8_str = ussd_decode(dcs, data_len, data);
+
+ if (!utf8_str) {
+ utf8_str = "";
+ status = OFONO_USSD_STATUS_NOTIFY;
+ } else
+ utf8_str_valid = TRUE;
/* 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,
@@ -363,7 +375,7 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const char
*str)
&variant);
dbus_message_iter_append_basic(&variant, DBUS_TYPE_STRING,
- &str);
+ &utf8_str);
dbus_message_iter_close_container(&iter, &variant);
@@ -375,10 +387,7 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const
char *str)
} else if (ussd->state == USSD_STATE_RESPONSE_SENT) {
reply = dbus_message_new_method_return(ussd->pending);
- if (!str)
- str = "";
-
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &str,
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &utf8_str,
DBUS_TYPE_INVALID);
if (status == OFONO_USSD_STATUS_ACTION_REQUIRED)
@@ -398,20 +407,17 @@ void ofono_ussd_notify(struct ofono_ussd *ussd, int status, const
char *str)
signal_name = "NotificationReceived";
}
- if (!str)
- str = "";
-
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:
@@ -419,6 +425,10 @@ out:
dbus_message_unref(ussd->pending);
ussd->pending = NULL;
+
+free:
+ if (utf8_str_valid)
+ g_free(utf8_str);
}
static void ussd_callback(const struct ofono_error *error, void *data)
@@ -447,6 +457,12 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage
*msg,
{
struct ofono_ussd *ussd = data;
const char *str;
+ int dcs = 0x0f;
+ unsigned char buf[256];
+ unsigned char *converted;
+ unsigned char *packed = NULL;
+ long num_packed;
+ long written;
if (ussd->pending)
return __ofono_error_busy(msg);
@@ -469,14 +485,27 @@ static DBusMessage *ussd_initiate(DBusConnection *conn, DBusMessage
*msg,
if (!valid_ussd_string(str))
return __ofono_error_invalid_format(msg);
- DBG("OK, running USSD request");
+ converted = convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0);
+ if (!converted)
+ return __ofono_error_invalid_format(msg);
+
+ packed = pack_7bit_own_buf(converted, written, 0, TRUE,
+ &num_packed, 0, buf);
+
+ g_free(converted);
+
+ if (num_packed > 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 = 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;
}
@@ -507,6 +536,12 @@ static DBusMessage *ussd_respond(DBusConnection *conn, DBusMessage
*msg,
{
struct ofono_ussd *ussd = data;
const char *str;
+ int dcs = 0x0f;
+ unsigned char buf[256];
+ unsigned char *converted;
+ unsigned char *packed = NULL;
+ long num_packed;
+ long written;
if (ussd->pending)
return __ofono_error_busy(msg);
@@ -521,12 +556,25 @@ static DBusMessage *ussd_respond(DBusConnection *conn, DBusMessage
*msg,
if (strlen(str) == 0)
return __ofono_error_invalid_format(msg);
+ converted = convert_utf8_to_gsm(str, strlen(str), NULL, &written, 0);
+ if (!converted)
+ return __ofono_error_invalid_format(msg);
+
+ packed = pack_7bit_own_buf(converted, written, 0, TRUE,
+ &num_packed, 0, buf);
+
+ g_free(converted);
+
+ if (num_packed > MAX_USSD_LENGTH)
+ return __ofono_error_invalid_args(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);
+ ussd->driver->request(ussd, dcs, packed, (int) num_packed,
+ ussd_response_callback, ussd);
return NULL;
}
@@ -752,3 +800,4 @@ void *ofono_ussd_get_data(struct ofono_ussd *ussd)
{
return ussd->driver_data;
}
+
--
1.7.0.4