From 11764921a03c89b221335ae815268c1acc373d19 Mon Sep 17 00:00:00 2001
From: Pavel Baturko <pabftk@gmail.com>
Date: Sat, 29 Sep 2012 01:57:06 +0000
Subject: [PATCH] USSD: Add decoding UCS2 USSD messages. UCS2 text is converted to UTF-8 and if terminal supports UTF-8 text will be printed, if not - hex representation of text will be printed.

---
 src/host/layer23/src/mobile/app_mobile.c |    8 ++++
 src/host/layer23/src/mobile/gsm480_ss.c  |   63 +++++++++++++++++++++--------
 2 files changed, 53 insertions(+), 18 deletions(-)

diff --git a/src/host/layer23/src/mobile/app_mobile.c b/src/host/layer23/src/mobile/app_mobile.c
index 09ff785..d59ab56 100644
--- a/src/host/layer23/src/mobile/app_mobile.c
+++ b/src/host/layer23/src/mobile/app_mobile.c
@@ -376,6 +376,12 @@ static struct vty_app_info vty_info = {
 	.go_parent_cb = ms_vty_go_parent,
 };
 
+static uint8_t terminal_utf8_support = 0;
+uint8_t get_terminal_utf8_support()
+{
+	return terminal_utf8_support;
+}
+
 /* global init */
 int l23_app_init(int (*mncc_recv)(struct osmocom_ms *ms, int, void *),
 	const char *config_file, const char *vty_ip, uint16_t vty_port)
@@ -407,6 +413,8 @@ int l23_app_init(int (*mncc_recv)(struct osmocom_ms *ms, int, void *),
 		return rc;
 	printf("VTY available on port %u.\n", vty_port);
 
+	terminal_utf8_support = osmo_check_utf8_locale();
+
 	osmo_signal_register_handler(SS_GLOBAL, &global_signal_cb, NULL);
 	osmo_signal_register_handler(SS_L1CTL, &mobile_signal_cb, NULL);
 	osmo_signal_register_handler(SS_L1CTL, &gsm322_l1_signal, NULL);
diff --git a/src/host/layer23/src/mobile/gsm480_ss.c b/src/host/layer23/src/mobile/gsm480_ss.c
index fda6288..f4d543c 100644
--- a/src/host/layer23/src/mobile/gsm480_ss.c
+++ b/src/host/layer23/src/mobile/gsm480_ss.c
@@ -35,6 +35,7 @@
 #include <osmocom/bb/mobile/vty.h>
 #include <osmocom/gsm/protocol/gsm_04_80.h>
 #include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/gsm0411_utils.h>
 
 static uint32_t new_callref = 0x80000001;
 
@@ -733,6 +734,9 @@ static int gsm480_rx_ussd(struct gsm_trans *trans, const uint8_t *data,
 	int i;
 	const uint8_t *tag_data;
 	int tag_len;
+	enum sms_alphabet alphabet;
+	uint8_t dcs;
+	uint16_t utf8_text_length;
 
 	/* sequence tag */
 	if (parse_tag_asn1(data, len, &tag_data, &tag_len) < 0) {
@@ -755,10 +759,9 @@ static int gsm480_rx_ussd(struct gsm_trans *trans, const uint8_t *data,
 		LOGP(DSS, LOGL_NOTICE, "Expecting DSC tag\n");
 		return -EINVAL;
 	}
-	if (tag_data[0] != 0x0f) {
-		LOGP(DSS, LOGL_NOTICE, "DSC not 0x0f\n");
-		return -EINVAL;
-	}
+	
+	dcs = tag_data[0];
+	alphabet = gsm338_get_sms_alphabet(dcs);
 	len -= tag_data - data + tag_len;
 	data = tag_data + tag_len;
 
@@ -771,21 +774,45 @@ static int gsm480_rx_ussd(struct gsm_trans *trans, const uint8_t *data,
 		LOGP(DSS, LOGL_NOTICE, "Expecting text tag\n");
 		return -EINVAL;
 	}
-	num_chars = tag_len * 8 / 7;
-	/* Prevent a mobile-originated buffer-overrun! */
-	if (num_chars > sizeof(text) - 1)
-		num_chars = sizeof(text) - 1;
-	text[sizeof(text) - 1] = '\0';
-	gsm_7bit_decode(text, tag_data, num_chars);
-
-	for (i = 0; text[i]; i++) {
-		if (text[i] == '\r')
-			text[i] = '\n';
+	switch (alphabet) {
+	case DCS_7BIT_DEFAULT:
+		/* Default 7 bit charset */
+		num_chars = tag_len * 8 / 7;
+		/* Prevent a mobile-originated buffer-overrun! */
+		if (num_chars > sizeof(text) - 1)
+			num_chars = sizeof(text) - 1;
+		text[sizeof(text) - 1] = '\0';
+		gsm_7bit_decode(text, tag_data, num_chars);
+
+		for (i = 0; text[i]; i++) {
+			if (text[i] == '\r')
+				text[i] = '\n';
+		}
+		/* remove last CR, if exists */
+		if (text[0] && text[strlen(text) - 1] == '\n')
+			text[strlen(text) - 1] = '\0';
+		gsm480_ss_result(trans->ms, text, 0);
+		break;
+	case DCS_UCS2:
+		/* USC2 charset, see ISO/IEC 10646 */
+		num_chars = tag_len / 2;
+		utf8_text_length = osmo_ucs2_to_utf8_decode(text, sizeof(text), tag_data, num_chars);
+		
+		if (get_terminal_utf8_support()) {
+			LOGP(DSS, LOGL_NOTICE, "Received USSD (UTF-8, text):\n%s\n",
+				text);
+			sprintf(text, "USSD was printed(decoded from UCS2 to UTF-8)");
+		} else {
+			LOGP(DSS, LOGL_NOTICE, "Received USSD (UTF-8, hex):\n%s\n", 
+				osmo_hexdump(text, utf8_text_length));
+			sprintf(text, "USSD was printed in hex(locale not UTF-8)");
+		}
+		gsm480_ss_result(trans->ms, text, 0);
+		break;
+	default:
+		LOGP(DSS, LOGL_NOTICE, "DSC <%d> unknown\n", dcs);
+		return -EINVAL;
 	}
-	/* remove last CR, if exists */
-	if (text[0] && text[strlen(text) - 1] == '\n')
-		text[strlen(text) - 1] = '\0';
-	gsm480_ss_result(trans->ms, text, 0);
 
 	return 0;
 }
-- 
1.7.2.5

