From 49fe2a82639e7e2fe5300693e935d1cbf6aff705 Mon Sep 17 00:00:00 2001
From: Pavel Baturko <pabftk@gmail.com>
Date: Sun, 20 Jan 2013 23:26:28 +0000
Subject: [PATCH] Add decoding UCS2 to UTF8, Extend gsm338_get_sms_alphabet to support more DCSs, Added function to check availability of UFT-8

---
 include/osmocom/gsm/gsm_utils.h |    2 ++
 src/gsm/gsm0411_utils.c         |    3 ++-
 src/gsm/gsm_utils.c             |   31 +++++++++++++++++++++++++++++++
 src/gsm/libosmogsm.map          |    1 +
 src/utils.c                     |   30 ++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+), 1 deletions(-)

diff --git a/include/osmocom/gsm/gsm_utils.h b/include/osmocom/gsm/gsm_utils.h
index 1767898..523e727 100644
--- a/include/osmocom/gsm/gsm_utils.h
+++ b/include/osmocom/gsm/gsm_utils.h
@@ -56,6 +56,8 @@ enum gsm_band {
 const char *gsm_band_name(enum gsm_band band);
 enum gsm_band gsm_band_parse(const char *mhz);
 
+int ucs2_to_utf8_decode(char *decoded, uint16_t decoded_buf_length, const uint8_t *user_data, uint8_t length);
+
 int gsm_7bit_decode(char *decoded, const uint8_t *user_data, uint8_t length);
 int gsm_7bit_decode_hdr(char *decoded, const uint8_t *user_data, uint8_t length, uint8_t ud_hdr_ind);
 int gsm_7bit_encode(uint8_t *result, const char *data);
diff --git a/src/gsm/gsm0411_utils.c b/src/gsm/gsm0411_utils.c
index fe69bf4..d6c4482 100644
--- a/src/gsm/gsm0411_utils.c
+++ b/src/gsm/gsm0411_utils.c
@@ -231,7 +231,7 @@ enum sms_alphabet gsm338_get_sms_alphabet(uint8_t dcs)
 	uint8_t cgbits = dcs >> 4;
 	enum sms_alphabet alpha = DCS_NONE;
 
-	if ((cgbits & 0xc) == 0) {
+	if ((cgbits & 0x08) == 0) {
 		if (cgbits & 2) {
 			LOGP(DLSMS, LOGL_NOTICE,
 			     "Compressed SMS not supported yet\n");
@@ -240,6 +240,7 @@ enum sms_alphabet gsm338_get_sms_alphabet(uint8_t dcs)
 
 		switch ((dcs >> 2)&0x03) {
 		case 0:
+		case 3:
 			alpha = DCS_7BIT_DEFAULT;
 			break;
 		case 1:
diff --git a/src/gsm/gsm_utils.c b/src/gsm/gsm_utils.c
index ecebde8..0d665de 100644
--- a/src/gsm/gsm_utils.c
+++ b/src/gsm/gsm_utils.c
@@ -102,6 +102,37 @@ static unsigned char gsm_7bit_alphabet[] = {
 	0xff, 0x7d, 0x08, 0xff, 0xff, 0xff, 0x7c, 0xff, 0x0c, 0x06, 0xff, 0xff, 0x7e, 0xff, 0xff
 };
 
+/* Convert UCS2 char to UTF8 char. Taken from Ben Bullock (lemoda.net) */
+int ucs2_to_utf8_decode(char *decoded, uint16_t decoded_buf_length, const uint8_t *user_data, uint8_t length)
+{
+	int i, j = 0;
+
+	for (i = 0; i < length; i++) {
+		int ucs2;
+
+		ucs2 = ((user_data[2 * i] << 8) | user_data[2 * i + 1]);
+		if (ucs2 < 0x80) {
+			if (j >= decoded_buf_length-1)
+				break;
+			decoded[j++] = ucs2;
+		} else if (ucs2 >= 0x80  && ucs2 < 0x800) {
+			if (j >= decoded_buf_length-2)
+				break;
+			decoded[j++] = (ucs2 >> 6)   | 0xC0;
+			decoded[j++] = (ucs2 & 0x3F) | 0x80;
+		} else if (ucs2 >= 0x800 && ucs2 < 0xFFFF) {
+			if (j >= decoded_buf_length-3)
+				break;
+			decoded[j++] = ((ucs2 >> 12)       ) | 0xE0;
+			decoded[j++] = ((ucs2 >> 6 ) & 0x3F) | 0x80;
+			decoded[j++] = ((ucs2      ) & 0x3F) | 0x80;
+		}
+	}
+	decoded[j] = '\0';
+
+	return j;
+}
+
 /* GSM 03.38 6.2.1 Character lookup for decoding */
 static int gsm_septet_lookup(uint8_t ch)
 {
diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map
index b2278f1..cdca3c8 100644
--- a/src/gsm/libosmogsm.map
+++ b/src/gsm/libosmogsm.map
@@ -134,6 +134,7 @@ gsm48_rr_att_tlvdef;
 gsm_7bit_decode;
 gsm_7bit_decode_hdr;
 gsm_7bit_encode;
+ucs2_to_utf8_decode;
 
 gsm_arfcn2band;
 gsm_arfcn2freq10;
diff --git a/src/utils.c b/src/utils.c
index c36979c..8c66b81 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -220,4 +220,34 @@ void osmo_str2upper(char *out, const char *in)
 }
 #endif /* HAVE_CTYPE_H */
 
+/*! \brief Check if terminal supports UFT-8 locale
+ *  \returns 1 if terminal supports UTF-8, 0 - otherwise
+ *
+ * This function will try to execute external 'locale' command 
+ * and check if system contains 'utf-8' locale.
+ */
+unsigned check_utf8_locale()
+{
+	FILE *cmd_pipe;
+	char available_locales[128];
+	unsigned i;
+	unsigned have_utf8_locale = 0;
+
+	cmd_pipe = popen("locale -a", "r");
+	if (cmd_pipe != NULL) {
+		while (fgets(available_locales, sizeof(available_locales), cmd_pipe) != NULL) {
+			for (i = 0; i < strlen(available_locales); i++)
+				available_locales[i] = tolower(available_locales[i]);
+			if ((strstr(available_locales, "utf-8") != NULL) || 
+				(strstr(available_locales, "utf8" ) != NULL)) {
+				have_utf8_locale = 1;
+				break;
+			}
+		}
+		pclose(cmd_pipe);
+	}
+
+	return have_utf8_locale;
+}
+
 /*! @} */
-- 
1.7.2.5

