gsm: fix operator name on Option devices with UCS2 charset
This commit is contained in:
@@ -87,6 +87,22 @@ charset_iconv_to (MMModemCharset charset)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
charset_iconv_from (MMModemCharset charset)
|
||||
{
|
||||
CharsetEntry *iter = &charset_map[0];
|
||||
|
||||
g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL);
|
||||
|
||||
while (iter->gsm_name) {
|
||||
if (iter->charset == charset)
|
||||
return iter->iconv_from_name;
|
||||
iter++;
|
||||
}
|
||||
g_warn_if_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_modem_charset_byte_array_append (GByteArray *array,
|
||||
const char *string,
|
||||
@@ -131,3 +147,79 @@ mm_modem_charset_byte_array_append (GByteArray *array,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* From hostap, Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> */
|
||||
|
||||
static int hex2num (char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int hex2byte (const char *hex)
|
||||
{
|
||||
int a, b;
|
||||
a = hex2num(*hex++);
|
||||
if (a < 0)
|
||||
return -1;
|
||||
b = hex2num(*hex++);
|
||||
if (b < 0)
|
||||
return -1;
|
||||
return (a << 4) | b;
|
||||
}
|
||||
|
||||
static char *
|
||||
hexstr2bin (const char *hex, gsize *out_len)
|
||||
{
|
||||
size_t len = strlen (hex);
|
||||
size_t i;
|
||||
int a;
|
||||
const char * ipos = hex;
|
||||
char * buf = NULL;
|
||||
char * opos;
|
||||
|
||||
/* Length must be a multiple of 2 */
|
||||
g_return_val_if_fail ((len % 2) == 0, NULL);
|
||||
|
||||
opos = buf = g_malloc0 ((len / 2) + 1);
|
||||
for (i = 0; i < len; i += 2) {
|
||||
a = hex2byte (ipos);
|
||||
if (a < 0) {
|
||||
g_free (buf);
|
||||
return NULL;
|
||||
}
|
||||
*opos++ = a;
|
||||
ipos += 2;
|
||||
}
|
||||
*out_len = len / 2;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* End from hostap */
|
||||
|
||||
char *
|
||||
mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset)
|
||||
{
|
||||
char *unconverted;
|
||||
const char *iconv_from;
|
||||
gsize unconverted_len = 0;
|
||||
|
||||
g_return_val_if_fail (src != NULL, NULL);
|
||||
g_return_val_if_fail (charset != MM_MODEM_CHARSET_UNKNOWN, NULL);
|
||||
|
||||
iconv_from = charset_iconv_from (charset);
|
||||
g_return_val_if_fail (iconv_from != NULL, FALSE);
|
||||
|
||||
unconverted = hexstr2bin (src, &unconverted_len);
|
||||
g_return_val_if_fail (unconverted != NULL, NULL);
|
||||
|
||||
if (charset == MM_MODEM_CHARSET_UTF8 || charset == MM_MODEM_CHARSET_IRA)
|
||||
return unconverted;
|
||||
|
||||
return g_convert (unconverted, unconverted_len, "UTF-8//TRANSLIT", iconv_from, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
|
@@ -43,5 +43,10 @@ gboolean mm_modem_charset_byte_array_append (GByteArray *array,
|
||||
gboolean quoted,
|
||||
MMModemCharset charset);
|
||||
|
||||
/* Take a string in hex representation ("00430052" or "A4BE11" for example)
|
||||
* and convert it from the given character set to UTF-8.
|
||||
*/
|
||||
char *mm_modem_charset_hex_to_utf8 (const char *src, MMModemCharset charset);
|
||||
|
||||
#endif /* MM_CHARSETS_H */
|
||||
|
||||
|
@@ -1408,8 +1408,37 @@ reg_info_updated (MMGenericGsm *self,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
convert_operator_from_ucs2 (char **operator)
|
||||
{
|
||||
const char *p;
|
||||
char *converted;
|
||||
size_t len;
|
||||
|
||||
g_return_if_fail (operator != NULL);
|
||||
g_return_if_fail (*operator != NULL);
|
||||
|
||||
p = *operator;
|
||||
len = strlen (p);
|
||||
|
||||
/* Len needs to be a multiple of 4 for UCS2 */
|
||||
if ((len < 4) && ((len % 4) != 0))
|
||||
return;
|
||||
|
||||
while (*p) {
|
||||
if (!isxdigit (*p++))
|
||||
return;
|
||||
}
|
||||
|
||||
converted = mm_modem_charset_hex_to_utf8 (*operator, MM_MODEM_CHARSET_UCS2);
|
||||
if (converted) {
|
||||
g_free (*operator);
|
||||
*operator = converted;
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
parse_operator (const char *reply)
|
||||
parse_operator (const char *reply, MMModemCharset cur_charset)
|
||||
{
|
||||
char *operator = NULL;
|
||||
|
||||
@@ -1431,6 +1460,13 @@ parse_operator (const char *reply)
|
||||
g_regex_unref (r);
|
||||
}
|
||||
|
||||
/* Some modems (Option & HSO) return the operator name as a hexadecimal
|
||||
* string of the bytes of the operator name as encoded by the current
|
||||
* character set.
|
||||
*/
|
||||
if (operator && (cur_charset == MM_MODEM_CHARSET_UCS2))
|
||||
convert_operator_from_ucs2 (&operator);
|
||||
|
||||
return operator;
|
||||
}
|
||||
|
||||
@@ -1444,7 +1480,7 @@ read_operator_code_done (MMAtSerialPort *port,
|
||||
char *oper;
|
||||
|
||||
if (!error) {
|
||||
oper = parse_operator (response->str);
|
||||
oper = parse_operator (response->str, MM_MODEM_CHARSET_UNKNOWN);
|
||||
if (oper)
|
||||
reg_info_updated (self, FALSE, 0, TRUE, oper, FALSE, NULL);
|
||||
}
|
||||
@@ -1457,10 +1493,11 @@ read_operator_name_done (MMAtSerialPort *port,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMGenericGsm *self = MM_GENERIC_GSM (user_data);
|
||||
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
|
||||
char *oper;
|
||||
|
||||
if (!error) {
|
||||
oper = parse_operator (response->str);
|
||||
oper = parse_operator (response->str, priv->cur_charset);
|
||||
if (oper)
|
||||
reg_info_updated (self, FALSE, 0, FALSE, NULL, TRUE, oper);
|
||||
}
|
||||
|
Reference in New Issue
Block a user