From d8be565fc564cbd6e3beaddb3fc77b311abf2359 Mon Sep 17 00:00:00 2001 From: Brandon Bayer Date: Mon, 16 Nov 2015 09:59:15 -0600 Subject: feat: implement IRA->GSM character set encoding & decoding This adds support for certain characters like @ $ ~ ^ --- configure.in | 2 +- src/pdu.c | 20 ++++++++++++++++++++ src/pdu.h | 4 ++++ src/pdu_decode.c | 25 +++++++++++++++++++++++++ src/pdu_encode.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/utils.c | 13 +++++++++++++ src/utils.h | 2 ++ 7 files changed, 110 insertions(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 2c4b8ad..71f19ec 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ AC_INIT([src/sms_main.c]) -AM_INIT_AUTOMAKE([sms-utils], [0.0.9]) +AM_INIT_AUTOMAKE([sms-utils], [0.0.10]) AM_CONFIG_HEADER([config.h]) AC_PROG_CC diff --git a/src/pdu.c b/src/pdu.c index 2ceb7ae..07a976c 100644 --- a/src/pdu.c +++ b/src/pdu.c @@ -36,6 +36,26 @@ #include "pdu.h" #include "sms_utils.h" +// ` is not a conversion, just a untranslatable letter +char strGSMTable[GSM_TABLE_SIZE] = { + '@','£','$','¥','è','é','ù','ì','ò','Ç','\n','Ø','ø','\r','Å','å', + 'Δ','_','Φ','Γ','Λ','Ω','Π','Ψ','Σ','Θ','Ξ','`','Æ','æ','ß','É', + ' ','!','\"','#','¤','%','&','\'','(',')','*','=',',','-','.','/', + '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?', + '¡','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O', + 'P','Q','R','S','T','U','V','W','X','Y','Z','Ä','Ö','Ñ','Ü','`', + '¿','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o', + 'p','q','r','s','t','u','v','w','x','y','z','ä','ö','ñ','ü','à'}; +char strExtendedTable[GSM_TABLE_SIZE] = { + '`','`','`','`','`','`','`','`','`','`','`','`','`','`','`','`', + '`','`','`','`','^','`','`','`','`','`','`','`','`','`','`','`', + '`','`','`','`','`','`','`','`','{','}','`','`','`','`','`','\\', + '`','`','`','`','`','`','`','`','`','`','`','`','[','~',']','`', + '|','`','`','`','`','`','`','`','`','`','`','`','`','`','`','`', + '`','`','`','`','`','`','`','`','`','`','`','`','`','`','`','`', + '`','`','`','`','`','€','`','`','`','`','`','`','`','`','`','`', + '`','`','`','`','`','`','`','`','`','`','`','`','`','`','`','`'}; + int hex_nibble_scan(const char *buf, size_t len) { static const char digits[] = "0123456789ABCDEF"; diff --git a/src/pdu.h b/src/pdu.h index 58f88e0..9dfddd4 100644 --- a/src/pdu.h +++ b/src/pdu.h @@ -25,6 +25,10 @@ extern char *strptime(const char *s, const char *format, struct tm *tm); #define PDU_VPF_RELATIVE_2DAYS 0xA8 +#define GSM_TABLE_SIZE 128 +extern char strGSMTable[]; +extern char strExtendedTable[]; + struct pdu_addr { char addr[PDU_ADDR_SIZE]; uint8_t type; diff --git a/src/pdu_decode.c b/src/pdu_decode.c index 140fd14..934aef5 100644 --- a/src/pdu_decode.c +++ b/src/pdu_decode.c @@ -309,6 +309,31 @@ int pdu_decode_user_data(const char *pdu_str, struct pdu_info *pdu, int *nr_octe pdu->user_data[i] = '\0'; } + //Only for 7-bit character sets + if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT)) { + int read = 0; + int store = 0; + + log_debug("Converting from GSM character set to IRA"); + for (read = 0; read < pdu->user_data_len; read++) { + if (pdu->user_data[read] == 0x1B) { + //Character from the extended set using the escape char (27) + read++; + log_debug("GSM before: 0x1B%02X | IRA after: 0x%02X", pdu->user_data[read], strExtendedTable[pdu->user_data[read]]); + pdu->user_data[store] = strExtendedTable[pdu->user_data[read]]; + } + else { + log_debug("GSM before: 0x%02X | IRA after: 0x%02X", pdu->user_data[read], strGSMTable[pdu->user_data[read]]); + pdu->user_data[store] = strGSMTable[pdu->user_data[read]]; + } + store++; + } + //Update lengths + pdu->user_data_len -= read - store; + pdu_str -= (read - store) * HEX_BYTE_LEN; + } + return pdu_str - begin; } diff --git a/src/pdu_encode.c b/src/pdu_encode.c index 1bb7e4d..f0d8c96 100644 --- a/src/pdu_encode.c +++ b/src/pdu_encode.c @@ -182,6 +182,51 @@ int pdu_encode_user_data(char *pdu_str, size_t len, struct pdu_info *pdu, int *n return -1; } + + //Convert to GSM character set, Only for 7-bit character sets + if ((pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) || + (pdu->data_coding.general.alphabet == PDU_ALPHABET_CDMA_DEFAULT)) { + int read = 0; + int store = 0; + char initial_user_data[PDU_UD_7BIT_MAX]; + + for (read = 0; read < pdu->user_data_len; read++) { + initial_user_data[read] = pdu->user_data[read]; + } + initial_user_data[read] = 0; + + log_debug("Converting from IRA character set to GSM"); + for (read = 0; read < pdu->user_data_len; read++) { + int GSMchar = indexOfChar(strGSMTable, GSM_TABLE_SIZE, initial_user_data[read]); + + if (GSMchar >= 0) { + log_debug("IRA before: 0x%02X | GSM after: 0x%02X", initial_user_data[read], GSMchar); + pdu->user_data[store] = GSMchar; + } + else { + //Check in extended table + GSMchar = indexOfChar(strExtendedTable, GSM_TABLE_SIZE, initial_user_data[read]); + + if (GSMchar >= 0) { + log_debug("IRA before: 0x%02X | GSM after: 0x1B%02X", initial_user_data[read], GSMchar); + pdu->user_data[store] = 0x1B; + store++; + pdu->user_data[store] = GSMchar; + } + else { + log_debug("IRA before: 0x%02X | Translation not found - no change", initial_user_data[read]); + pdu->user_data[store] = initial_user_data[read]; + } + } + + store++; + } + + //Update lengths + pdu->user_data_len += store - read; + } + + if (pdu->data_coding.general.alphabet == PDU_ALPHABET_DEFAULT) { if (pdu->user_data_len > PDU_UD_7BIT_MAX) { log_error("string exceeds 7-bit data max length"); diff --git a/src/utils.c b/src/utils.c index a794f9b..8e7bed7 100644 --- a/src/utils.c +++ b/src/utils.c @@ -275,3 +275,16 @@ char *device_lock(const char *path) return lock; } + +int indexOfChar(const char *array, int len, char character) +{ + int i; + + for (i = 0; i < len; i++) { + if (array[i] == character) { + return i; + } + } + return -1; +} + diff --git a/src/utils.h b/src/utils.h index 79b04ae..04a71b6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -37,6 +37,8 @@ char *shell_path_expand(const char *path); char *device_lock(const char *path); +int indexOfChar(const char *array, int len, char character); + #define YAML_INDENT 2 #define indentf(n, format, args...) \ -- cgit v1.2.3