38
62
while (isspace (*p))
69
/*****************************************************************************/
72
mm_count_bits_set (gulong number)
76
for (c = 0; number; c++)
81
/*****************************************************************************/
84
mm_create_device_identifier (guint vid,
89
const gchar *revision,
93
GString *devid, *msg = NULL;
95
gchar *p, *ret = NULL;
96
gchar str_vid[10], str_pid[10];
98
/* Build up the device identifier */
99
devid = g_string_sized_new (50);
101
g_string_append (devid, ati);
103
/* Only append "ATI1" if it's differnet than "ATI" */
104
if (!ati || (strcmp (ati, ati1) != 0))
105
g_string_append (devid, ati1);
108
g_string_append (devid, gsn);
110
g_string_append (devid, revision);
112
g_string_append (devid, model);
114
g_string_append (devid, manf);
116
if (!strlen (devid->str)) {
117
g_string_free (devid, TRUE);
122
msg = g_string_sized_new (strlen (devid->str) + 17);
124
sum = g_checksum_new (G_CHECKSUM_SHA1);
127
snprintf (str_vid, sizeof (str_vid) - 1, "%08x", vid);
128
g_checksum_update (sum, (const guchar *) &str_vid[0], strlen (str_vid));
129
g_string_append_printf (msg, "%08x", vid);
132
snprintf (str_pid, sizeof (str_pid) - 1, "%08x", pid);
133
g_checksum_update (sum, (const guchar *) &str_pid[0], strlen (str_pid));
134
g_string_append_printf (msg, "%08x", pid);
138
/* Strip spaces and linebreaks */
139
if (!isblank (*p) && !isspace (*p) && isascii (*p)) {
140
g_checksum_update (sum, (const guchar *) p, 1);
141
g_string_append_c (msg, *p);
145
ret = g_strdup (g_checksum_get_string (sum));
146
g_checksum_free (sum);
148
mm_dbg ("Device ID source '%s'", msg->str);
149
mm_dbg ("Device ID '%s'", ret);
150
g_string_free (msg, TRUE);
151
g_string_free (devid, TRUE);
156
/*****************************************************************************/
159
mm_netmask_to_cidr (const gchar *netmask)
163
inet_pton (AF_INET, netmask, &num);
164
return mm_count_bits_set (num);
167
/*****************************************************************************/
170
mm_filter_current_bands (const GArray *supported_bands,
171
const GArray *current_bands)
173
/* We will assure that the list given in 'current' bands maps the list
174
* given in 'supported' bands, unless 'UNKNOWN' or 'ANY' is given, of
179
if (!supported_bands ||
180
supported_bands->len == 0 ||
182
current_bands->len == 0)
185
if (supported_bands->len == 1 &&
186
(g_array_index (supported_bands, MMModemBand, 0) == MM_MODEM_BAND_UNKNOWN ||
187
g_array_index (supported_bands, MMModemBand, 0) == MM_MODEM_BAND_ANY))
190
if (current_bands->len == 1 &&
191
(g_array_index (current_bands, MMModemBand, 0) == MM_MODEM_BAND_UNKNOWN ||
192
g_array_index (current_bands, MMModemBand, 0) == MM_MODEM_BAND_ANY))
195
filtered = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), current_bands->len);
197
for (i = 0; i < current_bands->len; i++) {
200
for (j = 0; j < supported_bands->len; j++) {
201
if (g_array_index (supported_bands, MMModemBand, j) == g_array_index (current_bands, MMModemBand, i)) {
202
g_array_append_val (filtered, g_array_index (current_bands, MMModemBand, i));
209
if (filtered->len == 0) {
210
g_array_unref (filtered);
217
/*****************************************************************************/
220
mm_new_iso8601_time (guint year,
226
gboolean have_offset,
231
str = g_string_sized_new (30);
232
g_string_append_printf (str, "%04d-%02d-%02dT%02d:%02d:%02d",
233
year, month, day, hour, minute, second);
235
if (offset_minutes >=0 ) {
236
g_string_append_printf (str, "+%02d:%02d",
238
offset_minutes % 60);
240
offset_minutes *= -1;
241
g_string_append_printf (str, "-%02d:%02d",
243
offset_minutes % 60);
246
return g_string_free (str, FALSE);
249
/*****************************************************************************/
252
mm_filter_supported_modes (const GArray *all,
253
const GArray *supported_combinations)
255
MMModemModeCombination all_item;
257
GArray *filtered_combinations;
258
gboolean all_item_added = FALSE;
260
g_return_val_if_fail (all != NULL, NULL);
261
g_return_val_if_fail (all->len == 1, NULL);
262
g_return_val_if_fail (supported_combinations != NULL, NULL);
264
all_item = g_array_index (all, MMModemModeCombination, 0);
265
g_return_val_if_fail (all_item.allowed != MM_MODEM_MODE_NONE, NULL);
267
/* We will filter out all combinations which have modes not listed in 'all' */
268
filtered_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), supported_combinations->len);
269
for (i = 0; i < supported_combinations->len; i++) {
270
MMModemModeCombination *mode;
272
mode = &g_array_index (supported_combinations, MMModemModeCombination, i);
273
if (!(mode->allowed & ~all_item.allowed)) {
274
/* Compare only 'allowed', *not* preferred. If there is at least one item with allowed
275
* containing all supported modes, we're already good to go. This allows us to have a
276
* default with preferred != NONE (e.g. Wavecom 2G modem with allowed=CS+2G and
278
if (all_item.allowed == mode->allowed)
279
all_item_added = TRUE;
280
g_array_append_val (filtered_combinations, *mode);
284
if (filtered_combinations->len == 0)
285
mm_warn ("All supported mode combinations were filtered out.");
287
/* Add default entry with the generic mask including all items */
288
if (!all_item_added) {
289
mm_dbg ("Adding an explicit item with all supported modes allowed");
290
g_array_append_val (filtered_combinations, all_item);
293
return filtered_combinations;
296
/*****************************************************************************/
299
mm_filter_supported_capabilities (MMModemCapability all,
300
const GArray *supported_combinations)
303
GArray *filtered_combinations;
305
g_return_val_if_fail (all != MM_MODEM_CAPABILITY_NONE, NULL);
306
g_return_val_if_fail (supported_combinations != NULL, NULL);
308
/* We will filter out all combinations which have modes not listed in 'all' */
309
filtered_combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemCapability), supported_combinations->len);
310
for (i = 0; i < supported_combinations->len; i++) {
311
MMModemCapability capability;
313
capability = g_array_index (supported_combinations, MMModemCapability, i);
314
if (!(capability & ~all))
315
g_array_append_val (filtered_combinations, capability);
318
if (filtered_combinations->len == 0)
319
mm_warn ("All supported capability combinations were filtered out.");
321
return filtered_combinations;
324
/*****************************************************************************/
326
/* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */
327
#define CREG1 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])"
329
/* +CREG: <n>,<stat> (GSM 07.07 CREG=1 solicited) */
330
#define CREG2 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])"
332
/* +CREG: <stat>,<lac>,<ci> (GSM 07.07 CREG=2 unsolicited) */
333
#define CREG3 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)"
335
/* +CREG: <n>,<stat>,<lac>,<ci> (GSM 07.07 solicited and some CREG=2 unsolicited) */
336
#define CREG4 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,]*)\\s*,\\s*([^,\\s]*)"
338
/* +CREG: <stat>,<lac>,<ci>,<AcT> (ETSI 27.007 CREG=2 unsolicited) */
339
#define CREG5 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])"
341
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */
342
#define CREG6 "\\+(CREG|CGREG|CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])"
344
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT?>,<something> (Samsung Wave S8500) */
345
/* '<CR><LF>+CREG: 2,1,000B,2816, B, C2816<CR><LF><CR><LF>OK<CR><LF>' */
346
#define CREG7 "\\+(CREG|CGREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*"
348
/* +CREG: <stat>,<lac>,<ci>,<AcT>,<RAC> (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */
349
#define CREG8 "\\+(CREG|CGREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])\\s*,\\s*([^,\\s]*)"
351
/* +CEREG: <stat>,<lac>,<rac>,<ci>,<AcT> (ETSI 27.007 v8.6 CREG=2 unsolicited with RAC) */
352
#define CEREG1 "\\+(CEREG):\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])"
354
/* +CEREG: <n>,<stat>,<lac>,<rac>,<ci>,<AcT> (ETSI 27.007 v8.6 CREG=2 solicited with RAC) */
355
#define CEREG2 "\\+(CEREG):\\s*0*([0-9]),\\s*0*([0-9])\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*0*([0-9])"
358
mm_3gpp_creg_regex_get (gboolean solicited)
360
GPtrArray *array = g_ptr_array_sized_new (10);
365
regex = g_regex_new (CREG1 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
367
regex = g_regex_new ("\\r\\n" CREG1 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
369
g_ptr_array_add (array, regex);
373
regex = g_regex_new (CREG2 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
375
regex = g_regex_new ("\\r\\n" CREG2 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
377
g_ptr_array_add (array, regex);
381
regex = g_regex_new (CREG3 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
383
regex = g_regex_new ("\\r\\n" CREG3 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
385
g_ptr_array_add (array, regex);
389
regex = g_regex_new (CREG4 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
391
regex = g_regex_new ("\\r\\n" CREG4 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
393
g_ptr_array_add (array, regex);
397
regex = g_regex_new (CREG5 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
399
regex = g_regex_new ("\\r\\n" CREG5 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
401
g_ptr_array_add (array, regex);
405
regex = g_regex_new (CREG6 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
407
regex = g_regex_new ("\\r\\n" CREG6 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
409
g_ptr_array_add (array, regex);
413
regex = g_regex_new (CREG7 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
415
regex = g_regex_new ("\\r\\n" CREG7 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
417
g_ptr_array_add (array, regex);
421
regex = g_regex_new (CREG8 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
423
regex = g_regex_new ("\\r\\n" CREG8 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
425
g_ptr_array_add (array, regex);
429
regex = g_regex_new (CEREG1 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
431
regex = g_regex_new ("\\r\\n" CEREG1 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
433
g_ptr_array_add (array, regex);
437
regex = g_regex_new (CEREG2 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
439
regex = g_regex_new ("\\r\\n" CEREG2 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
441
g_ptr_array_add (array, regex);
447
mm_3gpp_creg_regex_destroy (GPtrArray *array)
449
g_ptr_array_foreach (array, (GFunc) g_regex_unref, NULL);
450
g_ptr_array_free (array, TRUE);
453
/*************************************************************************/
456
mm_3gpp_ciev_regex_get (void)
458
return g_regex_new ("\\r\\n\\+CIEV: (.*),(\\d)\\r\\n",
459
G_REGEX_RAW | G_REGEX_OPTIMIZE,
464
/*************************************************************************/
467
mm_3gpp_cusd_regex_get (void)
469
return g_regex_new ("\\r\\n\\+CUSD:\\s*(.*)\\r\\n",
470
G_REGEX_RAW | G_REGEX_OPTIMIZE,
475
/*************************************************************************/
478
mm_3gpp_cmti_regex_get (void)
480
return g_regex_new ("\\r\\n\\+CMTI: \"(\\S+)\",(\\d+)\\r\\n",
481
G_REGEX_RAW | G_REGEX_OPTIMIZE,
487
mm_3gpp_cds_regex_get (void)
490
* <CR><LF>+CDS: 24<CR><LF>07914356060013F10659098136395339F6219011707193802190117071938030<CR><LF>
492
return g_regex_new ("\\r\\n\\+CDS:\\s*(\\d+)\\r\\n(.*)\\r\\n",
493
G_REGEX_RAW | G_REGEX_OPTIMIZE,
44
498
/*************************************************************************/
47
save_scan_value (GHashTable *hash, const char *key, GMatchInfo *info, guint32 num)
52
g_return_if_fail (info != NULL);
54
quoted = g_match_info_fetch (info, num);
58
len = strlen (quoted);
60
/* Unquote the item if needed */
61
if ((len >= 2) && (quoted[0] == '"') && (quoted[len - 1] == '"')) {
63
quoted[len - 1] = ' ';
64
quoted = g_strstrip (quoted);
67
if (!strlen (quoted)) {
72
g_hash_table_insert (hash, g_strdup (key), quoted);
75
/* If the response was successfully parsed (even if no valid entries were
76
* found) the pointer array will be returned.
79
mm_gsm_parse_scan_response (const char *reply, GError **error)
82
GPtrArray *results = NULL;
501
mm_3gpp_network_info_free (MM3gppNetworkInfo *info)
503
g_free (info->operator_long);
504
g_free (info->operator_short);
505
g_free (info->operator_code);
510
mm_3gpp_network_info_list_free (GList *info_list)
512
g_list_free_full (info_list, (GDestroyNotify) mm_3gpp_network_info_free);
515
static MMModemAccessTechnology
516
get_mm_access_tech_from_etsi_access_tech (guint act)
518
/* See ETSI TS 27.007 */
521
return MM_MODEM_ACCESS_TECHNOLOGY_GSM;
523
return MM_MODEM_ACCESS_TECHNOLOGY_GSM_COMPACT;
525
return MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
527
return MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
529
return MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
531
return MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
533
return MM_MODEM_ACCESS_TECHNOLOGY_HSPA;
535
return MM_MODEM_ACCESS_TECHNOLOGY_LTE;
537
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
541
static MMModem3gppNetworkAvailability
542
parse_network_status (const gchar *str)
544
/* Expecting a value between '0' and '3' inclusive */
549
mm_warn ("Cannot parse network status: '%s'", str);
550
return MM_MODEM_3GPP_NETWORK_AVAILABILITY_UNKNOWN;
553
return (MMModem3gppNetworkAvailability) (str[0] - '0');
556
static MMModemAccessTechnology
557
parse_access_tech (const gchar *str)
559
/* Recognized access technologies are between '0' and '7' inclusive... */
564
mm_warn ("Cannot parse access tech: '%s'", str);
565
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
568
return get_mm_access_tech_from_etsi_access_tech (str[0] - '0');
572
mm_3gpp_parse_cops_test_response (const gchar *reply,
576
GList *info_list = NULL;
84
577
GMatchInfo *match_info;
86
578
gboolean umts_format = TRUE;
579
GError *inner_error = NULL;
88
581
g_return_val_if_fail (reply != NULL, NULL);
209
714
g_match_info_free (match_info);
210
715
g_regex_unref (r);
216
mm_gsm_destroy_scan_data (gpointer data)
218
GPtrArray *results = (GPtrArray *) data;
220
g_ptr_array_foreach (results, (GFunc) g_hash_table_destroy, NULL);
221
g_ptr_array_free (results, TRUE);
224
/*************************************************************************/
226
/* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */
227
#define CREG1 "\\+(CREG|CGREG):\\s*(\\d{1})"
229
/* +CREG: <n>,<stat> (GSM 07.07 CREG=1 solicited) */
230
#define CREG2 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})"
232
/* +CREG: <stat>,<lac>,<ci> (GSM 07.07 CREG=2 unsolicited) */
233
#define CREG3 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)"
235
/* +CREG: <n>,<stat>,<lac>,<ci> (GSM 07.07 solicited and some CREG=2 unsolicited) */
236
#define CREG4 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,]*)\\s*,\\s*([^,\\s]*)"
238
/* +CREG: <stat>,<lac>,<ci>,<AcT> (ETSI 27.007 CREG=2 unsolicited) */
239
#define CREG5 "\\+(CREG|CGREG):\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})"
241
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */
242
#define CREG6 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})"
244
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT?>,<something> (Samsung Wave S8500) */
245
/* '<CR><LF>+CREG: 2,1,000B,2816, B, C2816<CR><LF><CR><LF>OK<CR><LF>' */
246
#define CREG7 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*[^,\\s]*"
248
/* +CREG: <stat>,<lac>,<ci>,<AcT>,<RAC> (ETSI 27.007 v9.20 CREG=2 unsolicited with RAC) */
249
#define CREG8 "\\+(CREG|CGREG):\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})\\s*,\\s*([^,\\s]*)"
252
mm_gsm_creg_regex_get (gboolean solicited)
254
GPtrArray *array = g_ptr_array_sized_new (7);
259
regex = g_regex_new (CREG1 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
261
regex = g_regex_new ("\\r\\n" CREG1 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
263
g_ptr_array_add (array, regex);
267
regex = g_regex_new (CREG2 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
269
regex = g_regex_new ("\\r\\n" CREG2 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
271
g_ptr_array_add (array, regex);
275
regex = g_regex_new (CREG3 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
277
regex = g_regex_new ("\\r\\n" CREG3 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
279
g_ptr_array_add (array, regex);
283
regex = g_regex_new (CREG4 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
285
regex = g_regex_new ("\\r\\n" CREG4 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
287
g_ptr_array_add (array, regex);
291
regex = g_regex_new (CREG5 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
293
regex = g_regex_new ("\\r\\n" CREG5 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
295
g_ptr_array_add (array, regex);
299
regex = g_regex_new (CREG6 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
301
regex = g_regex_new ("\\r\\n" CREG6 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
303
g_ptr_array_add (array, regex);
307
regex = g_regex_new (CREG7 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
309
regex = g_regex_new ("\\r\\n" CREG7 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
311
g_ptr_array_add (array, regex);
315
regex = g_regex_new (CREG8 "$", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
317
regex = g_regex_new ("\\r\\n" CREG8 "\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
319
g_ptr_array_add (array, regex);
325
mm_gsm_creg_regex_destroy (GPtrArray *array)
327
g_ptr_array_foreach (array, (GFunc) g_regex_unref, NULL);
328
g_ptr_array_free (array, TRUE);
720
/*************************************************************************/
724
mm_3gpp_pdp_context_format_free (MM3gppPdpContextFormat *format)
726
g_slice_free (MM3gppPdpContextFormat, format);
730
mm_3gpp_pdp_context_format_list_free (GList *pdp_format_list)
732
g_list_free_full (pdp_format_list, (GDestroyNotify) mm_3gpp_pdp_context_format_free);
736
mm_3gpp_parse_cgdcont_test_response (const gchar *response,
740
GMatchInfo *match_info;
741
GError *inner_error = NULL;
744
if (!response || !g_str_has_prefix (response, "+CGDCONT:")) {
745
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing +CGDCONT prefix");
749
r = g_regex_new ("\\+CGDCONT:\\s*\\((\\d+)-(\\d+)\\),\\(?\"(\\S+)\"",
750
G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
752
g_assert (r != NULL);
754
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
755
while (!inner_error && g_match_info_matches (match_info)) {
759
MMBearerIpFamily pdp_type;
762
pdp_type_str = mm_get_string_unquoted_from_match_info (match_info, 3);
763
pdp_type = mm_3gpp_get_ip_family_from_pdp_type (pdp_type_str);
764
if (pdp_type == MM_BEARER_IP_FAMILY_NONE)
765
mm_dbg ("Unhandled PDP type in CGDCONT=? reply: '%s'", pdp_type_str);
768
if (!mm_get_uint_from_match_info (match_info, 1, &min_cid))
769
mm_warn ("Invalid min CID in CGDCONT=? reply for PDP type '%s'", pdp_type_str);
772
if (!mm_get_uint_from_match_info (match_info, 2, &max_cid))
773
mm_warn ("Invalid max CID in CGDCONT=? reply for PDP type '%s'", pdp_type_str);
775
MM3gppPdpContextFormat *format;
777
format = g_slice_new (MM3gppPdpContextFormat);
778
format->pdp_type = pdp_type;
779
format->min_cid = min_cid;
780
format->max_cid = max_cid;
782
list = g_list_prepend (list, format);
787
g_free (pdp_type_str);
788
g_match_info_next (match_info, &inner_error);
791
g_match_info_free (match_info);
795
mm_warn ("Unexpected error matching +CGDCONT response: '%s'", inner_error->message);
796
g_error_free (inner_error);
802
/*************************************************************************/
805
mm_3gpp_pdp_context_free (MM3gppPdpContext *pdp)
808
g_slice_free (MM3gppPdpContext, pdp);
812
mm_3gpp_pdp_context_list_free (GList *list)
814
g_list_free_full (list, (GDestroyNotify) mm_3gpp_pdp_context_free);
818
mm_3gpp_pdp_context_cmp (MM3gppPdpContext *a,
821
return (a->cid - b->cid);
825
mm_3gpp_parse_cgdcont_read_response (const gchar *reply,
828
GError *inner_error = NULL;
830
GMatchInfo *match_info;
834
/* No APNs configured, all done */
838
r = g_regex_new ("\\+CGDCONT:\\s*(\\d+)\\s*,([^,\\)]*),([^,\\)]*),([^,\\)]*)",
839
G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
842
g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, &inner_error);
844
while (!inner_error &&
845
g_match_info_matches (match_info)) {
847
MMBearerIpFamily ip_family;
849
str = mm_get_string_unquoted_from_match_info (match_info, 2);
850
ip_family = mm_3gpp_get_ip_family_from_pdp_type (str);
851
if (ip_family == MM_BEARER_IP_FAMILY_NONE)
852
mm_dbg ("Ignoring PDP context type: '%s'", str);
854
MM3gppPdpContext *pdp;
856
pdp = g_slice_new0 (MM3gppPdpContext);
857
if (!mm_get_uint_from_match_info (match_info, 1, &pdp->cid)) {
858
inner_error = g_error_new (MM_CORE_ERROR,
859
MM_CORE_ERROR_FAILED,
860
"Couldn't parse CID from reply: '%s'",
864
pdp->pdp_type = ip_family;
865
pdp->apn = mm_get_string_unquoted_from_match_info (match_info, 3);
867
list = g_list_prepend (list, pdp);
871
g_match_info_next (match_info, &inner_error);
874
g_match_info_free (match_info);
879
mm_3gpp_pdp_context_list_free (list);
880
g_propagate_error (error, inner_error);
881
g_prefix_error (error, "Couldn't properly parse list of PDP contexts. ");
885
list = g_list_sort (list, (GCompareFunc)mm_3gpp_pdp_context_cmp);
331
890
/*************************************************************************/
486
*out_reg_state = (guint32) stat;
1071
/* 'roaming' is the last valid state */
1072
if (stat > MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) {
1073
mm_warn ("Registration State '%lu' is unknown", stat);
1074
stat = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN;
1077
*out_reg_state = (MMModem3gppRegistrationState) stat;
1078
if (stat != MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN) {
488
1079
/* Don't fill in lac/ci/act if the device's state is unknown */
496
/*************************************************************************/
499
mm_cdma_parse_spservice_response (const char *reply,
500
MMModemCdmaRegistrationState *out_cdma_1x_state,
501
MMModemCdmaRegistrationState *out_evdo_state)
1083
*out_act = get_mm_access_tech_from_etsi_access_tech (act);
1088
/*************************************************************************/
1090
#define CMGF_TAG "+CMGF:"
1093
mm_3gpp_parse_cmgf_test_response (const gchar *reply,
1094
gboolean *sms_pdu_supported,
1095
gboolean *sms_text_supported,
1099
GMatchInfo *match_info;
1101
guint32 min = -1, max = -1;
1103
/* Strip whitespace and response tag */
1104
if (g_str_has_prefix (reply, CMGF_TAG))
1105
reply += strlen (CMGF_TAG);
1106
while (isspace (*reply))
1109
r = g_regex_new ("\\(?\\s*(\\d+)\\s*[-,]?\\s*(\\d+)?\\s*\\)?", 0, 0, error);
1113
if (!g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) {
1116
MM_CORE_ERROR_FAILED,
1117
"Failed to parse CMGF query result '%s'",
1119
g_match_info_free (match_info);
1124
s = g_match_info_fetch (match_info, 1);
1129
s = g_match_info_fetch (match_info, 2);
1134
/* CMGF=0 for PDU mode */
1135
*sms_pdu_supported = (min == 0);
1137
/* CMGF=1 for Text mode */
1138
*sms_text_supported = (max >= 1);
1140
g_match_info_free (match_info);
1145
/*************************************************************************/
1148
storage_from_str (const gchar *str)
1150
if (g_str_equal (str, "SM"))
1151
return MM_SMS_STORAGE_SM;
1152
if (g_str_equal (str, "ME"))
1153
return MM_SMS_STORAGE_ME;
1154
if (g_str_equal (str, "MT"))
1155
return MM_SMS_STORAGE_MT;
1156
if (g_str_equal (str, "SR"))
1157
return MM_SMS_STORAGE_SR;
1158
if (g_str_equal (str, "BM"))
1159
return MM_SMS_STORAGE_BM;
1160
if (g_str_equal (str, "TA"))
1161
return MM_SMS_STORAGE_TA;
1162
return MM_SMS_STORAGE_UNKNOWN;
1166
mm_3gpp_parse_cpms_test_response (const gchar *reply,
1175
g_assert (mem1 != NULL);
1176
g_assert (mem2 != NULL);
1177
g_assert (mem3 != NULL);
1180
* +CPMS: ("SM","ME"),("SM","ME"),("SM","ME")
1182
split = g_strsplit_set (mm_strip_tag (reply, "+CPMS:"), "()", -1);
1186
r = g_regex_new ("\\s*\"([^,\\)]+)\"\\s*", 0, 0, NULL);
1189
for (i = 0; split[i]; i++) {
1190
GMatchInfo *match_info;
1192
/* Got a range group to match */
1193
if (g_regex_match_full (r, split[i], strlen (split[i]), 0, 0, &match_info, NULL)) {
1194
GArray *array = NULL;
1196
while (g_match_info_matches (match_info)) {
1199
str = g_match_info_fetch (match_info, 1);
1201
MMSmsStorage storage;
1204
array = g_array_new (FALSE, FALSE, sizeof (MMSmsStorage));
1206
storage = storage_from_str (str);
1207
g_array_append_val (array, storage);
1211
g_match_info_next (match_info, NULL);
1221
g_match_info_free (match_info);
1224
break; /* once we got the last group, exit... */
1230
g_warn_if_fail (*mem1 != NULL);
1231
g_warn_if_fail (*mem2 != NULL);
1232
g_warn_if_fail (*mem3 != NULL);
1234
return (*mem1 && *mem2 && *mem3);
1237
/*************************************************************************/
1240
mm_3gpp_parse_cscs_test_response (const gchar *reply,
1241
MMModemCharset *out_charsets)
1243
MMModemCharset charsets = MM_MODEM_CHARSET_UNKNOWN;
1245
GMatchInfo *match_info;
1247
gboolean success = FALSE;
1249
g_return_val_if_fail (reply != NULL, FALSE);
1250
g_return_val_if_fail (out_charsets != NULL, FALSE);
1252
/* Find the first '(' or '"'; the general format is:
1254
* +CSCS: ("IRA","GSM","UCS2")
1256
* but some devices (some Blackberries) don't include the ().
1258
p = strchr (reply, '(');
1262
p = strchr (reply, '"');
1267
/* Now parse each charset */
1268
r = g_regex_new ("\\s*([^,\\)]+)\\s*", 0, 0, NULL);
1272
if (g_regex_match_full (r, p, strlen (p), 0, 0, &match_info, NULL)) {
1273
while (g_match_info_matches (match_info)) {
1274
str = g_match_info_fetch (match_info, 1);
1275
charsets |= mm_modem_charset_from_string (str);
1278
g_match_info_next (match_info, NULL);
1282
g_match_info_free (match_info);
1286
*out_charsets = charsets;
1291
/*************************************************************************/
1294
mm_3gpp_parse_clck_test_response (const gchar *reply,
1295
MMModem3gppFacility *out_facilities)
1298
GMatchInfo *match_info;
1300
g_return_val_if_fail (reply != NULL, FALSE);
1301
g_return_val_if_fail (out_facilities != NULL, FALSE);
1303
/* the general format is:
1305
* +CLCK: ("SC","AO","AI","PN")
1307
reply = mm_strip_tag (reply, "+CLCK:");
1309
/* Now parse each facility */
1310
r = g_regex_new ("\\s*\"([^,\\)]+)\"\\s*", 0, 0, NULL);
1311
g_assert (r != NULL);
1313
*out_facilities = MM_MODEM_3GPP_FACILITY_NONE;
1314
if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) {
1315
while (g_match_info_matches (match_info)) {
1318
str = g_match_info_fetch (match_info, 1);
1320
*out_facilities |= mm_3gpp_acronym_to_facility (str);
1324
g_match_info_next (match_info, NULL);
1327
g_match_info_free (match_info);
1330
return (*out_facilities != MM_MODEM_3GPP_FACILITY_NONE);
1333
/*************************************************************************/
1336
mm_3gpp_parse_clck_write_response (const gchar *reply,
1340
GMatchInfo *match_info;
1341
gboolean success = FALSE;
1343
g_return_val_if_fail (reply != NULL, FALSE);
1344
g_return_val_if_fail (enabled != NULL, FALSE);
1346
reply = mm_strip_tag (reply, "+CLCK:");
1348
r = g_regex_new ("\\s*([01])\\s*", 0, 0, NULL);
1349
g_assert (r != NULL);
1351
if (g_regex_match (r, reply, 0, &match_info)) {
1354
str = g_match_info_fetch (match_info, 1);
1356
/* We're trying to match either '0' or '1',
1357
* so we don't expect any other thing */
1360
else if (*str == '1')
1363
g_assert_not_reached ();
1369
g_match_info_free (match_info);
1375
/*************************************************************************/
1378
mm_3gpp_parse_cnum_exec_response (const gchar *reply,
1381
GArray *array = NULL;
1383
GMatchInfo *match_info;
1385
/* Empty strings also return NULL list */
1386
if (!reply || !reply[0])
1389
r = g_regex_new ("\\+CNUM:\\s*((\"([^\"]|(\\\"))*\")|([^,]*)),\"(?<num>\\S+)\",\\d",
1390
G_REGEX_UNGREEDY, 0, NULL);
1391
g_assert (r != NULL);
1393
g_regex_match (r, reply, 0, &match_info);
1394
while (g_match_info_matches (match_info)) {
1397
number = g_match_info_fetch_named (match_info, "num");
1399
if (number && number[0]) {
1401
array = g_array_new (TRUE, TRUE, sizeof (gchar *));
1402
g_array_append_val (array, number);
1406
g_match_info_next (match_info, NULL);
1409
g_match_info_free (match_info);
1412
return (array ? (GStrv) g_array_free (array, FALSE) : NULL);
1415
/*************************************************************************/
1417
struct MM3gppCindResponse {
1424
static MM3gppCindResponse *
1425
cind_response_new (const gchar *desc, guint idx, gint min, gint max)
1427
MM3gppCindResponse *r;
1430
g_return_val_if_fail (desc != NULL, NULL);
1431
g_return_val_if_fail (idx >= 0, NULL);
1433
r = g_malloc0 (sizeof (MM3gppCindResponse));
1436
r->desc = p = g_malloc0 (strlen (desc) + 1);
1438
if (*desc != '"' && !isspace (*desc))
1439
*p++ = tolower (*desc);
1450
cind_response_free (MM3gppCindResponse *r)
1452
g_return_if_fail (r != NULL);
1455
memset (r, 0, sizeof (MM3gppCindResponse));
1460
mm_3gpp_cind_response_get_desc (MM3gppCindResponse *r)
1462
g_return_val_if_fail (r != NULL, NULL);
1468
mm_3gpp_cind_response_get_index (MM3gppCindResponse *r)
1470
g_return_val_if_fail (r != NULL, 0);
1476
mm_3gpp_cind_response_get_min (MM3gppCindResponse *r)
1478
g_return_val_if_fail (r != NULL, -1);
1484
mm_3gpp_cind_response_get_max (MM3gppCindResponse *r)
1486
g_return_val_if_fail (r != NULL, -1);
1491
#define CIND_TAG "+CIND:"
1494
mm_3gpp_parse_cind_test_response (const gchar *reply,
1499
GMatchInfo *match_info;
1502
g_return_val_if_fail (reply != NULL, NULL);
1504
/* Strip whitespace and response tag */
1505
if (g_str_has_prefix (reply, CIND_TAG))
1506
reply += strlen (CIND_TAG);
1507
while (isspace (*reply))
1510
r = g_regex_new ("\\(([^,]*),\\((\\d+)[-,](\\d+).*\\)", G_REGEX_UNGREEDY, 0, NULL);
1512
g_set_error_literal (error,
1513
MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
1514
"Could not parse scan results.");
1518
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) cind_response_free);
1520
if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) {
1521
while (g_match_info_matches (match_info)) {
1522
MM3gppCindResponse *resp;
1524
gint min = 0, max = 0;
1526
desc = g_match_info_fetch (match_info, 1);
1528
tmp = g_match_info_fetch (match_info, 2);
1532
tmp = g_match_info_fetch (match_info, 3);
1536
resp = cind_response_new (desc, idx++, min, max);
1538
g_hash_table_insert (hash, g_strdup (resp->desc), resp);
1542
g_match_info_next (match_info, NULL);
1545
g_match_info_free (match_info);
1551
/*************************************************************************/
1554
mm_3gpp_parse_cind_read_response (const gchar *reply,
1557
GByteArray *array = NULL;
1559
GMatchInfo *match_info;
1560
GError *inner_error = NULL;
1563
g_return_val_if_fail (reply != NULL, NULL);
1565
if (!g_str_has_prefix (reply, CIND_TAG)) {
1566
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
1567
"Could not parse the +CIND response '%s': no CIND tag found",
1572
reply = mm_strip_tag (reply, CIND_TAG);
1574
r = g_regex_new ("(\\d+)[^0-9]+", G_REGEX_UNGREEDY, 0, NULL);
1575
g_assert (r != NULL);
1577
if (!g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) {
1578
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
1579
"Could not parse the +CIND response '%s': didn't match",
1584
array = g_byte_array_sized_new (g_match_info_get_match_count (match_info));
1586
/* Add a zero element so callers can use 1-based indexes returned by
1587
* mm_3gpp_cind_response_get_index().
1590
g_byte_array_append (array, &t, 1);
1592
while (!inner_error &&
1593
g_match_info_matches (match_info)) {
1597
str = g_match_info_fetch (match_info, 1);
1598
if (mm_get_uint_from_str (str, &val) && val < 255) {
1600
g_byte_array_append (array, &t, 1);
1602
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
1603
"Could not parse the +CIND response: invalid index '%s'",
1608
g_match_info_next (match_info, NULL);
1612
g_propagate_error (error, inner_error);
1613
g_byte_array_unref (array);
1618
g_match_info_free (match_info);
1624
/*************************************************************************/
1627
mm_3gpp_pdu_info_free (MM3gppPduInfo *info)
1634
mm_3gpp_pdu_info_list_free (GList *info_list)
1636
g_list_free_full (info_list, (GDestroyNotify)mm_3gpp_pdu_info_free);
1640
mm_3gpp_parse_pdu_cmgl_response (const gchar *str,
1643
GError *inner_error = NULL;
1645
GMatchInfo *match_info;
1649
* +CMGL: <index>, <status>, [<alpha>], <length>
1651
* +CMGL: <index>, <status>, <length>
1653
* We just read <index>, <stat> and the PDU itself.
1655
r = g_regex_new ("\\+CMGL:\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,(.*)\\r\\n([^\\r\\n]*)(\\r\\n)?",
1656
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
1657
g_assert (r != NULL);
1659
g_regex_match_full (r, str, strlen (str), 0, 0, &match_info, &inner_error);
1660
while (!inner_error && g_match_info_matches (match_info)) {
1661
MM3gppPduInfo *info;
1663
info = g_new0 (MM3gppPduInfo, 1);
1664
if (mm_get_int_from_match_info (match_info, 1, &info->index) &&
1665
mm_get_int_from_match_info (match_info, 2, &info->status) &&
1666
(info->pdu = mm_get_string_unquoted_from_match_info (match_info, 4)) != NULL) {
1667
/* Append to our list of results and keep on */
1668
list = g_list_append (list, info);
1669
g_match_info_next (match_info, &inner_error);
1671
inner_error = g_error_new (MM_CORE_ERROR,
1672
MM_CORE_ERROR_FAILED,
1673
"Error parsing +CMGL response: '%s'",
1678
g_match_info_free (match_info);
1682
g_propagate_error (error, inner_error);
1683
mm_3gpp_pdu_info_list_free (list);
1690
/*************************************************************************/
1692
/* Map two letter facility codes into flag values. There are
1693
* many more facilities defined (for various flavors of call
1694
* barring); we only map the ones we care about. */
1696
MMModem3gppFacility facility;
1700
static const FacilityAcronym facility_acronyms[] = {
1701
{ MM_MODEM_3GPP_FACILITY_SIM, "SC" },
1702
{ MM_MODEM_3GPP_FACILITY_PH_SIM, "PS" },
1703
{ MM_MODEM_3GPP_FACILITY_PH_FSIM, "PF" },
1704
{ MM_MODEM_3GPP_FACILITY_FIXED_DIALING, "FD" },
1705
{ MM_MODEM_3GPP_FACILITY_NET_PERS, "PN" },
1706
{ MM_MODEM_3GPP_FACILITY_NET_SUB_PERS, "PU" },
1707
{ MM_MODEM_3GPP_FACILITY_PROVIDER_PERS, "PP" },
1708
{ MM_MODEM_3GPP_FACILITY_CORP_PERS, "PC" }
1712
mm_3gpp_acronym_to_facility (const gchar *str)
1716
for (i = 0; i < G_N_ELEMENTS (facility_acronyms); i++) {
1717
if (g_str_equal (facility_acronyms[i].acronym, str))
1718
return facility_acronyms[i].facility;
1721
return MM_MODEM_3GPP_FACILITY_NONE;
1725
mm_3gpp_facility_to_acronym (MMModem3gppFacility facility)
1729
for (i = 0; i < G_N_ELEMENTS (facility_acronyms); i++) {
1730
if (facility_acronyms[i].facility == facility)
1731
return facility_acronyms[i].acronym;
1737
/*************************************************************************/
1739
MMModemAccessTechnology
1740
mm_string_to_access_tech (const gchar *string)
1742
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
1744
g_return_val_if_fail (string != NULL, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
1746
/* We're returning a MASK of technologies found; so we can include more
1747
* than one technology in the result */
1748
if (strcasestr (string, "LTE") || strcasestr (string, "4G"))
1749
act |= MM_MODEM_ACCESS_TECHNOLOGY_LTE;
1751
if (strcasestr (string, "HSPA+"))
1752
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA_PLUS;
1753
else if (strcasestr (string, "HSPA"))
1754
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA;
1757
if (strcasestr (string, "HSUPA"))
1758
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
1760
if (strcasestr (string, "HSDPA"))
1761
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
1763
if (strcasestr (string, "UMTS"))
1764
act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
1766
if (strcasestr (string, "EDGE"))
1767
act |= MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
1769
if (strcasestr (string, "GPRS"))
1770
act |= MM_MODEM_ACCESS_TECHNOLOGY_GPRS;
1772
if (strcasestr (string, "GSM"))
1773
act |= MM_MODEM_ACCESS_TECHNOLOGY_GSM;
1775
if (strcasestr (string, "EvDO Rel0"))
1776
act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
1778
if (strcasestr (string, "EvDO RelA"))
1779
act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDOA;
1781
if (strcasestr (string, "EvDO RelB"))
1782
act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDOB;
1784
if (strcasestr (string, "1xRTT") || strcasestr (string, "CDMA2000 1X"))
1785
act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
1790
/*************************************************************************/
1793
mm_3gpp_parse_operator (const gchar *reply,
1794
MMModemCharset cur_charset)
1796
gchar *operator = NULL;
1798
if (reply && !strncmp (reply, "+COPS: ", 7)) {
1799
/* Got valid reply */
1801
GMatchInfo *match_info;
1804
r = g_regex_new ("(\\d),(\\d),\"(.+)\"", G_REGEX_UNGREEDY, 0, NULL);
1808
g_regex_match (r, reply, 0, &match_info);
1809
if (g_match_info_matches (match_info))
1810
operator = g_match_info_fetch (match_info, 3);
1812
g_match_info_free (match_info);
1817
/* Some modems (Option & HSO) return the operator name as a hexadecimal
1818
* string of the bytes of the operator name as encoded by the current
1821
if (cur_charset == MM_MODEM_CHARSET_UCS2) {
1822
/* In this case we're already checking UTF-8 validity */
1823
operator = mm_charset_take_and_convert_to_utf8 (operator, MM_MODEM_CHARSET_UCS2);
1825
/* Ensure the operator name is valid UTF-8 so that we can send it
1826
* through D-Bus and such.
1828
else if (!g_utf8_validate (operator, -1, NULL)) {
1833
/* Some modems (Novatel LTE) return the operator name as "Unknown" when
1834
* it fails to obtain the operator name. Return NULL in such case.
1836
if (operator && g_ascii_strcasecmp (operator, "unknown") == 0) {
1845
/*************************************************************************/
1848
mm_3gpp_get_pdp_type_from_ip_family (MMBearerIpFamily family)
1851
case MM_BEARER_IP_FAMILY_IPV4:
1853
case MM_BEARER_IP_FAMILY_IPV6:
1855
case MM_BEARER_IP_FAMILY_IPV4V6:
1863
mm_3gpp_get_ip_family_from_pdp_type (const gchar *pdp_type)
1865
if (g_str_equal (pdp_type, "IP"))
1866
return MM_BEARER_IP_FAMILY_IPV4;
1867
if (g_str_equal (pdp_type, "IPV6"))
1868
return MM_BEARER_IP_FAMILY_IPV6;
1869
if (g_str_equal (pdp_type, "IPV4V6"))
1870
return MM_BEARER_IP_FAMILY_IPV4V6;
1871
return MM_BEARER_IP_FAMILY_NONE;
1874
/*************************************************************************/
1877
mm_3gpp_parse_operator_id (const gchar *operator_id,
1887
g_assert (operator_id != NULL);
1889
len = strlen (operator_id);
1890
if (len != 5 && len != 6) {
1893
MM_CORE_ERROR_FAILED,
1894
"Operator ID must have 5 or 6 digits");
1898
for (i = 0; i < len; i++) {
1899
if (!g_ascii_isdigit (operator_id[i])) {
1902
MM_CORE_ERROR_FAILED,
1903
"Operator ID must only contain digits");
1908
memcpy (&aux[0], operator_id, 3);
1914
MM_CORE_ERROR_FAILED,
1915
"MCC must not be zero");
1924
memcpy (&aux[0], &operator_id[3], 2);
1927
memcpy (&aux[0], &operator_id[3], 3);
1934
/*************************************************************************/
1937
mm_cdma_parse_spservice_read_response (const gchar *reply,
1938
MMModemCdmaRegistrationState *out_cdma_1x_state,
1939
MMModemCdmaRegistrationState *out_evdo_state)
505
1943
g_return_val_if_fail (reply != NULL, FALSE);
506
1944
g_return_val_if_fail (out_cdma_1x_state != NULL, FALSE);
767
2203
/*************************************************************************/
770
mm_gsm_parse_cscs_support_response (const char *reply,
771
MMModemCharset *out_charsets)
2206
mm_cdma_parse_crm_test_response (const gchar *reply,
2207
MMModemCdmaRmProtocol *min,
2208
MMModemCdmaRmProtocol *max,
773
MMModemCharset charsets = MM_MODEM_CHARSET_UNKNOWN;
2211
gboolean result = FALSE;
775
GMatchInfo *match_info;
2213
GMatchInfo *match_info = NULL;
2214
GError *match_error = NULL;
2216
/* Expected reply format is:
2221
r = g_regex_new ("\\+CRM:\\s*\\((\\d+)-(\\d+)\\)",
2222
G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
2224
g_assert (r != NULL);
2226
if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, &match_error)) {
2231
aux = g_match_info_fetch (match_info, 1);
2232
min_val = (guint) atoi (aux);
2235
aux = g_match_info_fetch (match_info, 2);
2236
max_val = (guint) atoi (aux);
2241
min_val >= max_val) {
2244
MM_CORE_ERROR_FAILED,
2245
"Couldn't parse CRM range: "
2246
"Unexpected range of RM protocols (%u,%u)",
2250
*min = mm_cdma_get_rm_protocol_from_index (min_val, error);
2251
if (*min != MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN) {
2252
*max = mm_cdma_get_rm_protocol_from_index (max_val, error);
2253
if (*max != MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN)
2257
} else if (match_error) {
2258
g_propagate_error (error, match_error);
2262
MM_CORE_ERROR_FAILED,
2263
"Couldn't parse CRM range: response didn't match (%s)",
2267
g_match_info_free (match_info);
2273
/*************************************************************************/
2275
MMModemCdmaRmProtocol
2276
mm_cdma_get_rm_protocol_from_index (guint index,
2281
/* just adding 1 from the index value should give us the enum */
2282
protocol = index + 1 ;
2283
if (protocol > MM_MODEM_CDMA_RM_PROTOCOL_STU_III) {
2286
MM_CORE_ERROR_FAILED,
2287
"Unexpected RM protocol index (%u)",
2289
protocol = MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN;
2292
return (MMModemCdmaRmProtocol)protocol;
2296
mm_cdma_get_index_from_rm_protocol (MMModemCdmaRmProtocol protocol,
2299
if (protocol == MM_MODEM_CDMA_RM_PROTOCOL_UNKNOWN) {
2302
MM_CORE_ERROR_FAILED,
2303
"Unexpected RM protocol (%s)",
2304
mm_modem_cdma_rm_protocol_get_string (protocol));
2308
/* just substracting 1 from the enum value should give us the index */
2309
return (protocol - 1);
2312
/*************************************************************************/
2315
mm_cdma_normalize_class (const gchar *orig_class)
2319
g_return_val_if_fail (orig_class != NULL, '0');
2321
class = toupper (orig_class[0]);
2323
/* Cellular (850MHz) */
2324
if (class == '1' || class == 'C')
2327
if (class == '2' || class == 'P')
2330
/* Unknown/not registered */
2334
/*************************************************************************/
2337
mm_cdma_normalize_band (const gchar *long_band,
2342
g_return_val_if_fail (long_band != NULL, 'Z');
2344
/* There are two response formats for the band; one includes the band
2345
* class and the other doesn't. For modems that include the band class
2346
* (ex Novatel S720) you'll see "Px" or "Cx" depending on whether the modem
2347
* is registered on a PCS/1900 (P) or Cellular/850 (C) system.
2349
band = toupper (long_band[0]);
2351
/* Possible band class in first position; return it */
2352
if (band == 'C' || band == 'P') {
2353
gchar tmp[2] = { band, '\0' };
2355
*out_class = mm_cdma_normalize_class (tmp);
2356
band = toupper (long_band[1]);
2359
/* normalize to A - F, and Z */
2360
if (band >= 'A' && band <= 'F')
2363
/* Unknown/not registered */
2367
/*************************************************************************/
2368
/* Caller must strip any "+GSN:" or "+CGSN" from @gsn */
2371
mm_parse_gsn (const char *gsn,
2376
gchar **items, **iter;
2377
gchar *meid = NULL, *esn = NULL, *imei = NULL, *p;
777
2378
gboolean success = FALSE;
779
g_return_val_if_fail (reply != NULL, FALSE);
780
g_return_val_if_fail (out_charsets != NULL, FALSE);
782
/* Find the first '(' or '"'; the general format is:
784
* +CSCS: ("IRA","GSM","UCS2")
786
* but some devices (some Blackberries) don't include the ().
788
p = strchr (reply, '(');
792
p = strchr (reply, '"');
797
/* Now parse each charset */
798
r = g_regex_new ("\\s*([^,\\)]+)\\s*", 0, 0, NULL);
2380
if (!gsn || !gsn[0])
802
if (g_regex_match_full (r, p, strlen (p), 0, 0, &match_info, NULL)) {
803
while (g_match_info_matches (match_info)) {
804
str = g_match_info_fetch (match_info, 1);
805
charsets |= mm_modem_charset_from_string (str);
808
g_match_info_next (match_info, NULL);
2383
/* IMEI is 15 numeric digits */
2385
/* ESNs take one of two formats:
2386
* (1) 7 or 8 hexadecimal digits
2387
* (2) 10 or 11 decimal digits
2389
* In addition, leading zeros may be present or absent, and hexadecimal
2390
* ESNs may or may not be prefixed with "0x".
2393
/* MEIDs take one of two formats:
2394
* (1) 14 hexadecimal digits, sometimes padded to 16 digits with leading zeros
2395
* (2) 18 decimal digits
2397
* As with ESNs, leading zeros may be present or absent, and hexadecimal
2398
* MEIDs may or may not be prefixed with "0x".
2401
items = g_strsplit_set (gsn, "\r\n\t: ,", 0);
2402
for (iter = items; iter && *iter && (!esn || !meid); iter++) {
2403
gboolean expect_hex = FALSE, is_hex, is_digit;
2410
if (g_str_has_prefix (s, "0x") || g_str_has_prefix (s, "0X")) {
2414
/* Skip any leading zeros */
2419
/* Check whether all digits are hex or decimal */
2420
is_hex = is_digit = TRUE;
2422
while (*p && (is_hex || is_digit)) {
2423
if (!g_ascii_isxdigit (*p))
2425
if (!g_ascii_isdigit (*p))
2430
/* Note that some hex strings are also valid digit strings */
2433
if (len == 7 || len == 8) {
2437
esn = g_strdup_printf ("0%s", s);
2441
} else if (len == 14) {
2444
meid = g_strdup (s);
2450
g_warn_if_fail (expect_hex == FALSE);
2454
imei = g_strdup (s);
2457
/* Decimal ESN/MEID unhandled for now; conversion from decimal to
2458
* hex isn't a straight dec->hex conversion, as the first 2 digits
2459
* of the ESN and first 3 digits of the MEID are the manufacturer
2460
* identifier and must be converted separately from serial number
2461
* and then concatenated with it.
812
g_match_info_free (match_info);
816
*out_charsets = charsets;
2467
success = meid || esn || imei;
821
/*************************************************************************/
824
mm_gsm_string_to_access_tech (const char *string)
826
g_return_val_if_fail (string != NULL, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN);
828
/* Better technologies are listed first since modems sometimes say
829
* stuff like "GPRS/EDGE" and that should be handled as EDGE.
831
if (strcasestr (string, "HSPA+"))
832
return MM_MODEM_GSM_ACCESS_TECH_HSPA_PLUS;
833
else if (strcasestr (string, "HSPA"))
834
return MM_MODEM_GSM_ACCESS_TECH_HSPA;
835
else if (strcasestr (string, "HSDPA/HSUPA"))
836
return MM_MODEM_GSM_ACCESS_TECH_HSPA;
837
else if (strcasestr (string, "HSUPA"))
838
return MM_MODEM_GSM_ACCESS_TECH_HSUPA;
839
else if (strcasestr (string, "HSDPA"))
840
return MM_MODEM_GSM_ACCESS_TECH_HSDPA;
841
else if (strcasestr (string, "UMTS"))
842
return MM_MODEM_GSM_ACCESS_TECH_UMTS;
843
else if (strcasestr (string, "EDGE"))
844
return MM_MODEM_GSM_ACCESS_TECH_EDGE;
845
else if (strcasestr (string, "GPRS"))
846
return MM_MODEM_GSM_ACCESS_TECH_GPRS;
847
else if (strcasestr (string, "GSM"))
848
return MM_MODEM_GSM_ACCESS_TECH_GSM;
850
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
853
/*************************************************************************/
856
mm_create_device_identifier (guint vid,
861
const char *revision,
865
GString *devid, *msg = NULL;
867
char *p, *ret = NULL;
868
char str_vid[10], str_pid[10];
870
/* Build up the device identifier */
871
devid = g_string_sized_new (50);
873
g_string_append (devid, ati);
875
/* Only append "ATI1" if it's differnet than "ATI" */
876
if (!ati || (strcmp (ati, ati1) != 0))
877
g_string_append (devid, ati1);
880
g_string_append (devid, gsn);
882
g_string_append (devid, revision);
884
g_string_append (devid, model);
886
g_string_append (devid, manf);
888
if (!strlen (devid->str)) {
889
g_string_free (devid, TRUE);
894
msg = g_string_sized_new (strlen (devid->str) + 17);
896
sum = g_checksum_new (G_CHECKSUM_SHA1);
899
snprintf (str_vid, sizeof (str_vid) - 1, "%08x", vid);
900
g_checksum_update (sum, (const guchar *) &str_vid[0], strlen (str_vid));
901
g_string_append_printf (msg, "%08x", vid);
904
snprintf (str_pid, sizeof (str_pid) - 1, "%08x", pid);
905
g_checksum_update (sum, (const guchar *) &str_pid[0], strlen (str_pid));
906
g_string_append_printf (msg, "%08x", pid);
910
/* Strip spaces and linebreaks */
911
if (!isblank (*p) && !isspace (*p) && isascii (*p)) {
912
g_checksum_update (sum, (const guchar *) p, 1);
913
g_string_append_c (msg, *p);
917
ret = g_strdup (g_checksum_get_string (sum));
918
g_checksum_free (sum);
920
mm_dbg ("Device ID source '%s'", msg->str);
921
mm_dbg ("Device ID '%s'", ret);
922
g_string_free (msg, TRUE);
923
g_string_free (devid, TRUE);
928
/*************************************************************************/
930
struct CindResponse {
937
static CindResponse *
938
cind_response_new (const char *desc, guint idx, gint min, gint max)
943
g_return_val_if_fail (desc != NULL, NULL);
944
g_return_val_if_fail (idx >= 0, NULL);
946
r = g_malloc0 (sizeof (CindResponse));
949
r->desc = p = g_malloc0 (strlen (desc) + 1);
951
if (*desc != '"' && !isspace (*desc))
952
*p++ = tolower (*desc);
963
cind_response_free (CindResponse *r)
965
g_return_if_fail (r != NULL);
968
memset (r, 0, sizeof (CindResponse));
973
cind_response_get_desc (CindResponse *r)
975
g_return_val_if_fail (r != NULL, NULL);
981
cind_response_get_index (CindResponse *r)
983
g_return_val_if_fail (r != NULL, 0);
989
cind_response_get_min (CindResponse *r)
991
g_return_val_if_fail (r != NULL, -1);
997
cind_response_get_max (CindResponse *r)
999
g_return_val_if_fail (r != NULL, -1);
1004
#define CIND_TAG "+CIND:"
1007
mm_parse_cind_test_response (const char *reply, GError **error)
1011
GMatchInfo *match_info;
1014
g_return_val_if_fail (reply != NULL, NULL);
1016
/* Strip whitespace and response tag */
1017
if (g_str_has_prefix (reply, CIND_TAG))
1018
reply += strlen (CIND_TAG);
1019
while (isspace (*reply))
1022
r = g_regex_new ("\\(([^,]*),\\((\\d+)[-,](\\d+)\\)", G_REGEX_UNGREEDY, 0, NULL);
1024
g_set_error_literal (error,
1025
MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
1026
"Could not parse scan results.");
1030
hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) cind_response_free);
1032
if (g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, NULL)) {
1033
while (g_match_info_matches (match_info)) {
1036
gint min = 0, max = 0;
1038
desc = g_match_info_fetch (match_info, 1);
1040
tmp = g_match_info_fetch (match_info, 2);
1044
tmp = g_match_info_fetch (match_info, 3);
1048
resp = cind_response_new (desc, idx++, min, max);
1050
g_hash_table_insert (hash, g_strdup (resp->desc), resp);
1054
g_match_info_next (match_info, NULL);
1057
g_match_info_free (match_info);
1064
mm_parse_cind_query_response(const char *reply, GError **error)
1066
GByteArray *array = NULL;
1067
const char *p = reply;
1069
GMatchInfo *match_info;
1072
g_return_val_if_fail (reply != NULL, NULL);
1074
if (!g_str_has_prefix (p, CIND_TAG)) {
1075
g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
1076
"Could not parse the +CIND response");
1080
p += strlen (CIND_TAG);
1081
while (isspace (*p))
1084
r = g_regex_new ("(\\d+)[^0-9]+", G_REGEX_UNGREEDY, 0, NULL);
1086
g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
1087
"Internal failure attempting to parse +CIND response");
1091
if (!g_regex_match_full (r, p, strlen (p), 0, 0, &match_info, NULL)) {
1092
g_set_error_literal (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
1093
"Failure parsing the +CIND response");
1097
array = g_byte_array_sized_new (g_match_info_get_match_count (match_info));
1099
/* Add a zero element so callers can use 1-based indexes returned by
1100
* cind_response_get_index().
1102
g_byte_array_append (array, &t, 1);
1104
while (g_match_info_matches (match_info)) {
1108
str = g_match_info_fetch (match_info, 1);
1111
val = strtoul (str, NULL, 10);
1114
if ((errno == 0) && (val < 255))
1116
/* FIXME: indicate errors somehow? */
1117
g_byte_array_append (array, &t, 1);
1120
g_match_info_next (match_info, NULL);
1124
g_match_info_free (match_info);