diff --git a/src/stkutil.c b/src/stkutil.c index 497ad5b4..bfe29674 100644 --- a/src/stkutil.c +++ b/src/stkutil.c @@ -30,3 +30,172 @@ #include #include "stkutil.h" +#include "smsutil.h" +#include "simutil.h" +#include "util.h" + +static gboolean parse_dataobj_text(struct stk_command *command, + struct comprehension_tlv_iter *iter) +{ + unsigned int len; + + if (comprehension_tlv_iter_next(iter) != TRUE) + return FALSE; + + if (comprehension_tlv_iter_get_tag(iter) != + STK_DATA_OBJECT_TYPE_TEXT) + return FALSE; + + len = comprehension_tlv_iter_get_length(iter); + + /* DCS followed by some text, cannot be 1 */ + if (len == 1) + return FALSE; + + if (len > 0) { + const unsigned char *data = + comprehension_tlv_iter_get_data(iter); + unsigned char dcs = data[0]; + char *utf8; + + switch (dcs) { + case 0x00: + { + long written; + unsigned long max_to_unpack = (len - 1) * 8 / 7; + unsigned char *unpacked = unpack_7bit(data + 1, len - 1, + 0, FALSE, + max_to_unpack, + &written, 0); + if (unpacked == NULL) + return FALSE; + + utf8 = convert_gsm_to_utf8(unpacked, written, + NULL, NULL, 0); + g_free(unpacked); + break; + } + case 0x04: + utf8 = convert_gsm_to_utf8(data + 1, len - 1, + NULL, NULL, 0); + break; + case 0x08: + utf8 = g_convert((const gchar *) data + 1, len - 1, + "UTF-8//TRANSLIT", "UCS-2BE", + NULL, NULL, NULL); + break; + default: + return FALSE;; + } + + if (utf8 == NULL) + return FALSE; + + command->display_text.text = utf8; + } else + command->display_text.text = NULL; + + return TRUE; +} + +static void destroy_display_text(struct stk_command *command) +{ + g_free(command->display_text.text); +} + +static gboolean parse_display_text(struct stk_command *command, + struct comprehension_tlv_iter *iter) +{ + if (parse_dataobj_text(command, iter) == FALSE) + return FALSE; + + command->destructor = destroy_display_text; + + return TRUE; +} + +struct stk_command *stk_command_new_from_pdu(const unsigned char *pdu, + unsigned int len) +{ + struct ber_tlv_iter ber; + struct comprehension_tlv_iter iter; + const unsigned char *data; + struct stk_command *command; + gboolean ok; + + ber_tlv_iter_init(&ber, pdu, len); + + if (ber_tlv_iter_next(&ber) != TRUE) + return NULL; + + /* We should be wrapped in a Proactive UICC Command Tag 0xD0 */ + if (ber_tlv_iter_get_short_tag(&ber) != 0xD0) + return NULL; + + ber_tlv_iter_recurse_comprehension(&ber, &iter); + + /* + * Now parse actual command details, they come in order with + * Command Details TLV first, followed by Device Identities TLV + */ + if (comprehension_tlv_iter_next(&iter) != TRUE) + return NULL; + + if (comprehension_tlv_iter_get_tag(&iter) != + STK_DATA_OBJECT_TYPE_COMMAND_DETAILS) + return NULL; + + if (comprehension_tlv_iter_get_length(&iter) != 0x03) + return NULL; + + data = comprehension_tlv_iter_get_data(&iter); + + command = g_new0(struct stk_command, 1); + + command->number = data[0]; + command->type = data[1]; + command->qualifier = data[2]; + + if (comprehension_tlv_iter_next(&iter) != TRUE) + goto fail; + + if (comprehension_tlv_iter_get_tag(&iter) != + STK_DATA_OBJECT_TYPE_DEVICE_IDENTITIES) + goto fail; + + if (comprehension_tlv_iter_get_length(&iter) != 0x02) + goto fail; + + data = comprehension_tlv_iter_get_data(&iter); + + command->src = data[0]; + command->dst = data[1]; + + switch (command->type) { + case STK_COMMAND_TYPE_DISPLAY_TEXT: + ok = parse_display_text(command, &iter); + break; + default: + ok = FALSE; + break; + }; + + if (ok) + return command; + +fail: + if (command->destructor) + command->destructor(command); + + g_free(command); + + return NULL; +} + +void stk_command_free(struct stk_command *command) +{ + if (command->destructor) + command->destructor(command); + + g_free(command); +} diff --git a/src/stkutil.h b/src/stkutil.h index 7e9ad86e..9fd71469 100644 --- a/src/stkutil.h +++ b/src/stkutil.h @@ -81,7 +81,7 @@ enum stk_command_type { enum stk_data_object_type { STK_DATA_OBJECT_TYPE_COMMAND_DETAILS = 0x01, - STK_DATA_OBJECT_TYPE_DEVICE_IDENTITY = 0x02, + STK_DATA_OBJECT_TYPE_DEVICE_IDENTITIES = 0x02, STK_DATA_OBJECT_TYPE_RESULT = 0x03, STK_DATA_OBJECT_TYPE_DURATION = 0x04, STK_DATA_OBJECT_TYPE_ALPHA_IDENTIFIER = 0x05, @@ -184,3 +184,28 @@ enum stk_device_identity_type { STK_DEVICE_IDENTITY_TYPE_TERMINAL = 0x82, STK_DEVICE_IDENTITY_TYPE_NETWORK = 0x83, }; + +struct stk_command_display_text { + char *text; + unsigned char icon_id; + unsigned char icon_qualifier; + ofono_bool_t immediate_response; +}; + +struct stk_command { + unsigned char number; + unsigned char type; + unsigned char qualifier; + enum stk_device_identity_type src; + enum stk_device_identity_type dst; + + union { + struct stk_command_display_text display_text; + }; + + void (*destructor)(struct stk_command *command); +}; + +struct stk_command *stk_command_new_from_pdu(const unsigned char *pdu, + unsigned int len); +void stk_command_free(struct stk_command *command);