gsm: fix operator name on Option devices with UCS2 charset

This commit is contained in:
Dan Williams
2010-03-16 16:45:32 -07:00
parent c18dfa67d8
commit 6266f949ba
3 changed files with 137 additions and 3 deletions

View File

@@ -87,6 +87,22 @@ charset_iconv_to (MMModemCharset charset)
return NULL; 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 gboolean
mm_modem_charset_byte_array_append (GByteArray *array, mm_modem_charset_byte_array_append (GByteArray *array,
const char *string, const char *string,
@@ -131,3 +147,79 @@ mm_modem_charset_byte_array_append (GByteArray *array,
return TRUE; 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);
}

View File

@@ -43,5 +43,10 @@ gboolean mm_modem_charset_byte_array_append (GByteArray *array,
gboolean quoted, gboolean quoted,
MMModemCharset charset); 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 */ #endif /* MM_CHARSETS_H */

View File

@@ -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 * static char *
parse_operator (const char *reply) parse_operator (const char *reply, MMModemCharset cur_charset)
{ {
char *operator = NULL; char *operator = NULL;
@@ -1431,6 +1460,13 @@ parse_operator (const char *reply)
g_regex_unref (r); 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; return operator;
} }
@@ -1444,7 +1480,7 @@ read_operator_code_done (MMAtSerialPort *port,
char *oper; char *oper;
if (!error) { if (!error) {
oper = parse_operator (response->str); oper = parse_operator (response->str, MM_MODEM_CHARSET_UNKNOWN);
if (oper) if (oper)
reg_info_updated (self, FALSE, 0, TRUE, oper, FALSE, NULL); reg_info_updated (self, FALSE, 0, TRUE, oper, FALSE, NULL);
} }
@@ -1457,10 +1493,11 @@ read_operator_name_done (MMAtSerialPort *port,
gpointer user_data) gpointer user_data)
{ {
MMGenericGsm *self = MM_GENERIC_GSM (user_data); MMGenericGsm *self = MM_GENERIC_GSM (user_data);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
char *oper; char *oper;
if (!error) { if (!error) {
oper = parse_operator (response->str); oper = parse_operator (response->str, priv->cur_charset);
if (oper) if (oper)
reg_info_updated (self, FALSE, 0, FALSE, NULL, TRUE, oper); reg_info_updated (self, FALSE, 0, FALSE, NULL, TRUE, oper);
} }