~ubuntu-branches/ubuntu/vivid/modemmanager/vivid-proposed

« back to all changes in this revision

Viewing changes to src/mm-generic-gsm.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael Biebl
  • Date: 2011-06-16 17:12:41 UTC
  • mfrom: (16.1.1 oneiric)
  • Revision ID: james.westby@ubuntu.com-20110616171241-k8vgsdmbpsvx467q
Tags: 0.4.997-1
* debian/watch: Switch to .bz2 tarballs.
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
121
121
    gboolean loc_signal;
122
122
 
123
123
    MMModemGsmUssdState ussd_state;
 
124
 
 
125
    /* SMS */
 
126
    GHashTable *sms_present;
124
127
} MMGenericGsmPrivate;
125
128
 
126
129
static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info);
272
275
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
273
276
    gboolean parsed = FALSE;
274
277
 
 
278
    /* If the modem has already been removed, return without
 
279
     * scheduling callback */
 
280
    if (mm_callback_info_check_modem_removed (info))
 
281
        return;
 
282
 
275
283
    if (error)
276
284
        info->error = g_error_copy (error);
277
285
    else if (response && strstr (response->str, "+CPIN: ")) {
510
518
    gboolean success = FALSE;
511
519
    char buf[21], swapped[21];
512
520
 
 
521
    /* If the modem has already been removed, return without
 
522
     * scheduling callback */
 
523
    if (mm_callback_info_check_modem_removed (info))
 
524
        return;
 
525
 
513
526
    if (error) {
514
527
        info->error = g_error_copy (error);
515
528
        goto done;
1061
1074
{
1062
1075
    MMCallbackInfo *info = user_data;
1063
1076
 
1064
 
    info->error = mm_modem_check_removed (info->modem, error);
1065
 
    if (info->modem) {
1066
 
        if (info->error) {
1067
 
            MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
1068
 
 
1069
 
            g_clear_error (&info->error);
1070
 
 
1071
 
            /* The modem doesn't like unsolicited CGREG, so we'll need to poll */
1072
 
            priv->cgreg_poll = TRUE;
1073
 
        } else
1074
 
            mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (1), NULL);
1075
 
 
1076
 
        /* Success; get initial state */
1077
 
        mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem);
1078
 
    }
 
1077
    /* If the modem has already been removed, return without
 
1078
     * scheduling callback */
 
1079
    if (mm_callback_info_check_modem_removed (info))
 
1080
        return;
 
1081
 
 
1082
    if (error) {
 
1083
        MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
 
1084
 
 
1085
        /* The modem doesn't like unsolicited CGREG, so we'll need to poll */
 
1086
        priv->cgreg_poll = TRUE;
 
1087
    } else
 
1088
        mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (1), NULL);
 
1089
 
 
1090
    /* Success; get initial state */
 
1091
    mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem);
1079
1092
 
1080
1093
    initial_unsolicited_reg_check_done (info);
1081
1094
}
1088
1101
{
1089
1102
    MMCallbackInfo *info = user_data;
1090
1103
 
1091
 
    /* Ignore errors except modem removal errors */
1092
 
    info->error = mm_modem_check_removed (info->modem, error);
1093
 
    if (info->modem) {
1094
 
        if (info->error) {
1095
 
            g_clear_error (&info->error);
1096
 
            /* Try CGREG=1 instead */
1097
 
            mm_at_serial_port_queue_command (port, "+CGREG=1", 3, cgreg1_done, info);
1098
 
        } else {
1099
 
            add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI);
1100
 
 
1101
 
            mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (2), NULL);
1102
 
 
1103
 
            /* Success; get initial state */
1104
 
            mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem);
1105
 
 
1106
 
            /* All done */
1107
 
            initial_unsolicited_reg_check_done (info);
1108
 
        }
 
1104
    /* If the modem has already been removed, return without
 
1105
     * scheduling callback */
 
1106
    if (mm_callback_info_check_modem_removed (info))
 
1107
        return;
 
1108
 
 
1109
    /* Ignore errors */
 
1110
    if (error) {
 
1111
        /* Try CGREG=1 instead */
 
1112
        mm_at_serial_port_queue_command (port, "+CGREG=1", 3, cgreg1_done, info);
1109
1113
    } else {
1110
 
        /* Modem got removed */
1111
 
        mm_callback_info_schedule (info);
 
1114
        add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI);
 
1115
 
 
1116
        mm_callback_info_set_data (info, CGREG_NUM_TAG, GUINT_TO_POINTER (2), NULL);
 
1117
 
 
1118
        /* Success; get initial state */
 
1119
        mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, info->modem);
 
1120
 
 
1121
        /* All done */
 
1122
        initial_unsolicited_reg_check_done (info);
1112
1123
    }
1113
1124
}
1114
1125
 
1119
1130
            gpointer user_data)
1120
1131
{
1121
1132
    MMCallbackInfo *info = user_data;
1122
 
 
1123
 
    info->error = mm_modem_check_removed (info->modem, error);
1124
 
    if (info->modem) {
1125
 
        MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
1126
 
 
1127
 
        if (info->error) {
1128
 
            g_clear_error (&info->error);
1129
 
 
1130
 
            /* The modem doesn't like unsolicited CREG, so we'll need to poll */
1131
 
            priv->creg_poll = TRUE;
1132
 
        } else
1133
 
            mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (1), NULL);
 
1133
    MMGenericGsmPrivate *priv;
 
1134
 
 
1135
    /* If the modem has already been removed, return without
 
1136
     * scheduling callback */
 
1137
    if (mm_callback_info_check_modem_removed (info))
 
1138
        return;
 
1139
 
 
1140
    priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
 
1141
 
 
1142
    if (error) {
 
1143
        /* The modem doesn't like unsolicited CREG, so we'll need to poll */
 
1144
        priv->creg_poll = TRUE;
 
1145
    } else
 
1146
        mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (1), NULL);
 
1147
 
 
1148
    /* Success; get initial state */
 
1149
    mm_at_serial_port_queue_command (port, "+CREG?", 10, reg_poll_response, info->modem);
 
1150
 
 
1151
    /* Now try to set up CGREG messages */
 
1152
    mm_at_serial_port_queue_command (port, "+CGREG=2", 3, cgreg2_done, info);
 
1153
}
 
1154
 
 
1155
static void
 
1156
creg2_done (MMAtSerialPort *port,
 
1157
            GString *response,
 
1158
            GError *error,
 
1159
            gpointer user_data)
 
1160
{
 
1161
    MMCallbackInfo *info = user_data;
 
1162
 
 
1163
    /* If the modem has already been removed, return without
 
1164
     * scheduling callback */
 
1165
    if (mm_callback_info_check_modem_removed (info))
 
1166
        return;
 
1167
 
 
1168
    /* Ignore errors */
 
1169
    if (error)
 
1170
        mm_at_serial_port_queue_command (port, "+CREG=1", 3, creg1_done, info);
 
1171
    else {
 
1172
        add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI);
 
1173
 
 
1174
        mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (2), NULL);
1134
1175
 
1135
1176
        /* Success; get initial state */
1136
1177
        mm_at_serial_port_queue_command (port, "+CREG?", 10, reg_poll_response, info->modem);
1137
1178
 
1138
1179
        /* Now try to set up CGREG messages */
1139
1180
        mm_at_serial_port_queue_command (port, "+CGREG=2", 3, cgreg2_done, info);
1140
 
    } else {
1141
 
        /* Modem got removed */
1142
 
        mm_callback_info_schedule (info);
1143
 
    }
1144
 
}
1145
 
 
1146
 
static void
1147
 
creg2_done (MMAtSerialPort *port,
1148
 
            GString *response,
1149
 
            GError *error,
1150
 
            gpointer user_data)
1151
 
{
1152
 
    MMCallbackInfo *info = user_data;
1153
 
 
1154
 
    /* Ignore errors except modem removal errors */
1155
 
    info->error = mm_modem_check_removed (info->modem, error);
1156
 
    if (info->modem) {
1157
 
        if (info->error) {
1158
 
            g_clear_error (&info->error);
1159
 
            mm_at_serial_port_queue_command (port, "+CREG=1", 3, creg1_done, info);
1160
 
        } else {
1161
 
            add_loc_capability (MM_GENERIC_GSM (info->modem), MM_MODEM_LOCATION_CAPABILITY_GSM_LAC_CI);
1162
 
 
1163
 
            mm_callback_info_set_data (info, CREG_NUM_TAG, GUINT_TO_POINTER (2), NULL);
1164
 
 
1165
 
            /* Success; get initial state */
1166
 
            mm_at_serial_port_queue_command (port, "+CREG?", 10, reg_poll_response, info->modem);
1167
 
 
1168
 
            /* Now try to set up CGREG messages */
1169
 
            mm_at_serial_port_queue_command (port, "+CGREG=2", 3, cgreg2_done, info);
1170
 
        }
1171
 
    } else {
1172
 
        /* Modem got removed */
1173
 
        mm_callback_info_schedule (info);
1174
1181
    }
1175
1182
}
1176
1183
 
1179
1186
{
1180
1187
    MMGenericGsmPrivate *priv;
1181
1188
 
1182
 
    info->error = mm_modem_check_removed (modem, error);
1183
 
 
1184
 
    if (modem) {
1185
 
        mm_modem_set_state (modem,
1186
 
                            MM_MODEM_STATE_DISABLED,
1187
 
                            MM_MODEM_STATE_REASON_NONE);
1188
 
 
1189
 
        priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
1190
 
 
1191
 
        if (priv->primary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->primary)))
1192
 
            mm_serial_port_close_force (MM_SERIAL_PORT (priv->primary));
1193
 
        if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary)))
1194
 
            mm_serial_port_close_force (MM_SERIAL_PORT (priv->secondary));
1195
 
    }
 
1189
    /* If modem already removed, do nothing */
 
1190
    if (!modem || mm_callback_info_check_modem_removed (info))
 
1191
        return;
 
1192
 
 
1193
    if (error)
 
1194
        info->error = g_error_copy (error);
 
1195
 
 
1196
    mm_modem_set_state (modem,
 
1197
                        MM_MODEM_STATE_DISABLED,
 
1198
                        MM_MODEM_STATE_REASON_NONE);
 
1199
 
 
1200
    priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
 
1201
 
 
1202
    if (priv->primary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->primary)))
 
1203
        mm_serial_port_close_force (MM_SERIAL_PORT (priv->primary));
 
1204
    if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary)))
 
1205
        mm_serial_port_close_force (MM_SERIAL_PORT (priv->secondary));
1196
1206
 
1197
1207
    mm_callback_info_schedule (info);
1198
1208
}
1312
1322
               gpointer user_data)
1313
1323
{
1314
1324
    MMGenericGsm *self = MM_GENERIC_GSM (user_data);
1315
 
 
1316
 
    guint idx=0;
 
1325
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
 
1326
    guint idx = 0;
1317
1327
    char *str;
1318
1328
 
1319
1329
    str = g_match_info_fetch (info, 2);
1321
1331
        idx = atoi (str);
1322
1332
    g_free (str);
1323
1333
 
 
1334
    /* Don't signal multiple times if there are multiple CMTI notifications for a message */
 
1335
    if (g_hash_table_lookup_extended (priv->sms_present, GINT_TO_POINTER (idx), NULL, NULL))
 
1336
        return;
 
1337
 
 
1338
    /* Nothing is currently stored in the hash table - presence is all that matters. */
 
1339
    g_hash_table_insert (priv->sms_present, GINT_TO_POINTER (idx), NULL);
 
1340
 
1324
1341
    /* todo: parse pdu to know if the sms is complete */
1325
1342
    mm_modem_gsm_sms_received (MM_MODEM_GSM_SMS (self),
1326
1343
                               idx,
1458
1475
{
1459
1476
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
1460
1477
 
 
1478
    /* If the modem has already been removed, return without
 
1479
     * scheduling callback */
 
1480
    if (mm_callback_info_check_modem_removed (info))
 
1481
        return;
 
1482
 
1461
1483
    /* Let subclasses handle the power up command response/error; many devices
1462
1484
     * don't support +CFUN, but for those that do let them handle the error
1463
1485
     * correctly.
1478
1500
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
1479
1501
    char *cmd = NULL;
1480
1502
 
 
1503
    /* If the modem has already been removed, return without
 
1504
     * scheduling callback */
 
1505
    if (mm_callback_info_check_modem_removed (info))
 
1506
        return;
 
1507
 
1481
1508
    if (error) {
1482
1509
        mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
1483
1510
        return;
1580
1607
{
1581
1608
    MMCallbackInfo *info = user_data;
1582
1609
 
1583
 
    info->error = mm_modem_check_removed (info->modem, error);
1584
 
    if (!info->error) {
 
1610
    /* If the modem has already been removed, return without
 
1611
     * scheduling callback */
 
1612
    if (mm_callback_info_check_modem_removed (info))
 
1613
        return;
 
1614
 
 
1615
    if (error)
 
1616
        info->error = g_error_copy (error);
 
1617
    else {
1585
1618
        MMGenericGsm *self = MM_GENERIC_GSM (info->modem);
1586
1619
 
1587
1620
        mm_serial_port_close_force (MM_SERIAL_PORT (port));
1615
1648
    MMModemState prev_state;
1616
1649
    char *cmd = NULL;
1617
1650
 
1618
 
    info->error = mm_modem_check_removed (info->modem, error);
1619
 
    if (info->error) {
1620
 
        if (info->modem) {
1621
 
            /* Reset old state since the operation failed */
1622
 
            prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG));
1623
 
            mm_modem_set_state (MM_MODEM (info->modem),
1624
 
                                prev_state,
1625
 
                                MM_MODEM_STATE_REASON_NONE);
1626
 
        }
 
1651
    /* If the modem has already been removed, return without
 
1652
     * scheduling callback */
 
1653
    if (mm_callback_info_check_modem_removed (info))
 
1654
        return;
 
1655
 
 
1656
    if (error) {
 
1657
        info->error = g_error_copy (error);
 
1658
 
 
1659
        /* Reset old state since the operation failed */
 
1660
        prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG));
 
1661
        mm_modem_set_state (MM_MODEM (info->modem),
 
1662
                            prev_state,
 
1663
                            MM_MODEM_STATE_REASON_NONE);
1627
1664
 
1628
1665
        mm_callback_info_schedule (info);
1629
1666
        return;
1731
1768
{
1732
1769
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
1733
1770
 
 
1771
    /* If the modem has already been removed, return without
 
1772
     * scheduling callback */
 
1773
    if (mm_callback_info_check_modem_removed (info))
 
1774
        return;
 
1775
 
1734
1776
    if (error)
1735
1777
        info->error = g_error_copy (error);
1736
1778
    else
1752
1794
    char hex[51];
1753
1795
    char *bin;
1754
1796
 
 
1797
    /* If the modem has already been removed, return without
 
1798
     * scheduling callback */
 
1799
    if (mm_callback_info_check_modem_removed (info))
 
1800
        return;
 
1801
 
1755
1802
    if (error) {
1756
1803
        info->error = g_error_copy (error);
1757
1804
        goto done;
1793
1840
                                       MM_MODEM_ERROR_GENERAL,
1794
1841
                                       "SIM returned malformed response '%s'",
1795
1842
                                       hex);
 
1843
            g_free (bin);
1796
1844
            goto done;
1797
1845
        }
1798
1846
 
1807
1855
                                       "SIM returned invalid MNC length %d (should be either 2 or 3)",
1808
1856
                                       mnc_len);
1809
1857
        }
 
1858
        g_free (bin);
1810
1859
    } else {
1811
1860
        info->error = g_error_new (MM_MODEM_ERROR,
1812
1861
                                   MM_MODEM_ERROR_GENERAL,
1844
1893
}
1845
1894
 
1846
1895
static void
 
1896
get_spn_done (MMAtSerialPort *port,
 
1897
              GString *response,
 
1898
              GError *error,
 
1899
              gpointer user_data)
 
1900
{
 
1901
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
 
1902
    int sw1, sw2;
 
1903
    gboolean success = FALSE;
 
1904
    char hex[51];
 
1905
    char *bin, *utf8;
 
1906
 
 
1907
    if (error) {
 
1908
        info->error = g_error_copy (error);
 
1909
        goto done;
 
1910
    }
 
1911
 
 
1912
    memset (hex, 0, sizeof (hex));
 
1913
    if (sscanf (response->str, "+CRSM:%d,%d,\"%50c\"", &sw1, &sw2, (char *) &hex) == 3)
 
1914
        success = TRUE;
 
1915
    else {
 
1916
        /* May not include quotes... */
 
1917
        if (sscanf (response->str, "+CRSM:%d,%d,%50c", &sw1, &sw2, (char *) &hex) == 3)
 
1918
            success = TRUE;
 
1919
    }
 
1920
 
 
1921
    if (!success) {
 
1922
        info->error = g_error_new_literal (MM_MODEM_ERROR,
 
1923
                                           MM_MODEM_ERROR_GENERAL,
 
1924
                                           "Could not parse the CRSM response");
 
1925
        goto done;
 
1926
    }
 
1927
 
 
1928
    if ((sw1 == 0x90 && sw2 == 0x00) || (sw1 == 0x91) || (sw1 == 0x92) || (sw1 == 0x9f)) {
 
1929
        gsize buflen = 0;
 
1930
 
 
1931
        /* Make sure the buffer is only hex characters */
 
1932
        while (buflen < sizeof (hex) && hex[buflen]) {
 
1933
            if (!isxdigit (hex[buflen])) {
 
1934
                hex[buflen] = 0x0;
 
1935
                break;
 
1936
            }
 
1937
            buflen++;
 
1938
        }
 
1939
 
 
1940
        /* Convert hex string to binary */
 
1941
        bin = utils_hexstr2bin (hex, &buflen);
 
1942
        if (!bin) {
 
1943
            info->error = g_error_new (MM_MODEM_ERROR,
 
1944
                                       MM_MODEM_ERROR_GENERAL,
 
1945
                                       "SIM returned malformed response '%s'",
 
1946
                                       hex);
 
1947
            goto done;
 
1948
        }
 
1949
 
 
1950
        /* Remove the FF filler at the end */
 
1951
        while (bin[buflen - 1] == (char)0xff)
 
1952
            buflen--;
 
1953
 
 
1954
        /* First byte is metadata; remainder is GSM-7 unpacked into octets; convert to UTF8 */
 
1955
        utf8 = (char *)mm_charset_gsm_unpacked_to_utf8 ((guint8 *)bin + 1, buflen - 1);
 
1956
        g_free(bin);
 
1957
        mm_callback_info_set_result(info, utf8, g_free);
 
1958
    } else {
 
1959
        info->error = g_error_new (MM_MODEM_ERROR,
 
1960
                                   MM_MODEM_ERROR_GENERAL,
 
1961
                                   "SIM failed to handle CRSM request (sw1 %d sw2 %d)",
 
1962
                                   sw1, sw2);
 
1963
    }
 
1964
 
 
1965
done:
 
1966
    mm_callback_info_schedule (info);
 
1967
}
 
1968
 
 
1969
 
 
1970
static void
1847
1971
get_imei (MMModemGsmCard *modem,
1848
1972
          MMModemStringFn callback,
1849
1973
          gpointer user_data)
1881
2005
}
1882
2006
 
1883
2007
static void
 
2008
get_spn (MMModemGsmCard *modem,
 
2009
         MMModemStringFn callback,
 
2010
         gpointer user_data)
 
2011
{
 
2012
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
 
2013
    MMCallbackInfo *info;
 
2014
 
 
2015
    info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
 
2016
 
 
2017
    /* READ BINARY of EFspn (Service Provider Name) ETSI 51.011 section 10.3.11 */
 
2018
    mm_at_serial_port_queue_command_cached (priv->primary,
 
2019
                                            "+CRSM=176,28486,0,0,17",
 
2020
                                            3,
 
2021
                                            get_spn_done,
 
2022
                                            info);
 
2023
}
 
2024
 
 
2025
static void
1884
2026
get_card_info (MMModem *modem,
1885
2027
               MMModemInfoFn callback,
1886
2028
               gpointer user_data)
1913
2055
pin_puk_recheck_done (MMModem *modem, GError *error, gpointer user_data)
1914
2056
{
1915
2057
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
 
2058
    MMGenericGsmPrivate *priv;
1916
2059
    MMSerialPort *port;
1917
2060
    GError *saved_error;
1918
2061
 
 
2062
    /* Do nothing if modem removed */
 
2063
    if (!modem || mm_callback_info_check_modem_removed (info))
 
2064
        return;
 
2065
 
 
2066
    priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
 
2067
 
1919
2068
    /* Clear the pin check timeout to ensure that it won't ever get a
1920
2069
     * stale MMCallbackInfo if the modem got removed.  We'll reschedule it here
1921
2070
     * anyway if needed.
1922
2071
     */
1923
 
    if (info->modem) {
1924
 
        MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
1925
 
 
1926
 
        if (priv->pin_check_timeout)
1927
 
            g_source_remove (priv->pin_check_timeout);
1928
 
        priv->pin_check_timeout = 0;
1929
 
    }
1930
 
 
1931
 
    /* modem could have been removed before we get here, in which case
1932
 
     * 'modem' will be NULL.
1933
 
     */
1934
 
    info->error = mm_modem_check_removed (modem, error);
 
2072
    if (priv->pin_check_timeout)
 
2073
        g_source_remove (priv->pin_check_timeout);
 
2074
    priv->pin_check_timeout = 0;
 
2075
 
 
2076
    /* Propagate the error to the info */
 
2077
    if (error)
 
2078
        info->error = g_error_copy (error);
1935
2079
 
1936
2080
    /* If the modem wasn't removed, and the modem isn't ready yet, ask it for
1937
2081
     * the current PIN status a few times since some devices take a bit to fully
1938
2082
     * enable themselves after a SIM PIN/PUK unlock.
1939
2083
     */
1940
 
    if (   info->modem
1941
 
        && info->error
1942
 
        && !g_error_matches (info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_REMOVED)) {
1943
 
        MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
1944
 
 
 
2084
    if (info->error && !g_error_matches (info->error, MM_MODEM_ERROR, MM_MODEM_ERROR_REMOVED)) {
1945
2085
        if (priv->pin_check_tries < 4) {
1946
2086
            g_clear_error (&info->error);
1947
2087
            priv->pin_check_tries++;
1952
2092
 
1953
2093
    /* Otherwise, clean up and return the PIN check result */
1954
2094
    port = mm_callback_info_get_data (info, PIN_PORT_TAG);
1955
 
    if (modem && port)
 
2095
    if (port)
1956
2096
        mm_serial_port_close (port);
1957
2097
 
1958
2098
    /* If we have a saved error from sending PIN/PUK, return that to callers */
1959
2099
    saved_error = mm_callback_info_get_data (info, SAVED_ERROR_TAG);
1960
2100
    if (saved_error) {
1961
 
        if (info->modem && !mm_modem_base_get_unlock_required (MM_MODEM_BASE (info->modem))) {
 
2101
        if (!mm_modem_base_get_unlock_required (MM_MODEM_BASE (info->modem))) {
1962
2102
            /* Original unlock failed but the modem is actually unlocked, so
1963
2103
             * return success.  Sometimes happens if the modem doesn't allow
1964
2104
             * CPIN="xxxx" when it's already unlocked and returns an error.
1982
2122
{
1983
2123
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
1984
2124
 
 
2125
    /* If the modem has already been removed, return without
 
2126
     * scheduling callback */
 
2127
    if (mm_callback_info_check_modem_removed (info))
 
2128
        return;
 
2129
 
1985
2130
    if (error) {
1986
2131
        if (error->domain != MM_MOBILE_ERROR) {
1987
2132
            info->error = g_error_copy (error);
2046
2191
{
2047
2192
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
2048
2193
 
 
2194
    /* If the modem has already been removed, return without
 
2195
     * scheduling callback */
 
2196
    if (mm_callback_info_check_modem_removed (info))
 
2197
        return;
 
2198
 
2049
2199
    if (error) {
2050
2200
        if (error->domain != MM_MOBILE_ERROR) {
2051
2201
            info->error = g_error_copy (error);
2109
2259
{
2110
2260
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
2111
2261
 
 
2262
    /* If the modem has already been removed, return without
 
2263
     * scheduling callback */
 
2264
    if (mm_callback_info_check_modem_removed (info))
 
2265
        return;
 
2266
 
2112
2267
    if (error)
2113
2268
        info->error = g_error_copy (error);
2114
2269
    mm_callback_info_schedule (info);
2139
2294
{
2140
2295
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
2141
2296
 
 
2297
    /* If the modem has already been removed, return without
 
2298
     * scheduling callback */
 
2299
    if (mm_callback_info_check_modem_removed (info))
 
2300
        return;
 
2301
 
2142
2302
    if (error)
2143
2303
        info->error = g_error_copy (error);
2144
2304
    mm_callback_info_schedule (info);
2631
2791
                     gpointer user_data)
2632
2792
{
2633
2793
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
2634
 
    MMGenericGsm *self = MM_GENERIC_GSM (info->modem);
2635
 
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
 
2794
    MMGenericGsm *self;
 
2795
    MMGenericGsmPrivate *priv;
2636
2796
    guint id;
2637
2797
    MMModemGsmNetworkRegStatus status;
2638
2798
 
 
2799
    /* If the modem has already been removed, return without
 
2800
     * scheduling callback */
 
2801
    if (mm_callback_info_check_modem_removed (info))
 
2802
        return;
 
2803
 
 
2804
    self = MM_GENERIC_GSM (info->modem);
 
2805
    priv = MM_GENERIC_GSM_GET_PRIVATE (self);
 
2806
 
2639
2807
    /* This function should only get called during the connect sequence when
2640
2808
     * polling for registration state, since explicit registration requests
2641
2809
     * from D-Bus clients are filled from the cached registration state.
2703
2871
               gpointer user_data)
2704
2872
{
2705
2873
    MMCallbackInfo *info = user_data;
2706
 
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
 
2874
    MMGenericGsmPrivate *priv;
2707
2875
 
2708
2876
    mm_callback_info_unref (info);
2709
2877
 
 
2878
    /* If the modem has already been removed, return without
 
2879
     * scheduling callback */
 
2880
    if (mm_callback_info_check_modem_removed (info))
 
2881
        return;
 
2882
 
 
2883
    priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
 
2884
 
2710
2885
    /* If the registration timed out (and thus pending_reg_info will be NULL)
2711
2886
     * and the modem eventually got around to sending the response for the
2712
2887
     * registration request then just ignore the response since the callback is
2883
3058
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
2884
3059
    GError *real_error;
2885
3060
 
 
3061
    /* If the modem has already been removed, return without
 
3062
     * scheduling callback */
 
3063
    if (mm_callback_info_check_modem_removed (info))
 
3064
        return;
 
3065
 
2886
3066
    /* If the CEER command was successful, copy that error reason into the
2887
3067
     * callback's error.  If not, use the original error.
2888
3068
     */
2912
3092
              gpointer user_data)
2913
3093
{
2914
3094
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
2915
 
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
 
3095
    MMGenericGsmPrivate *priv;
 
3096
 
 
3097
    /* If the modem has already been removed, return without
 
3098
     * scheduling callback */
 
3099
    if (mm_callback_info_check_modem_removed (info))
 
3100
        return;
 
3101
 
 
3102
    priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
2916
3103
 
2917
3104
    if (error) {
2918
3105
        info->error = g_error_copy (error);
2964
3151
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
2965
3152
    MMModemState prev_state;
2966
3153
 
2967
 
    info->error = mm_modem_check_removed (modem, error);
2968
 
    if (info->error) {
2969
 
        if (info->modem && modem) {
2970
 
            /* Reset old state since the operation failed */
2971
 
            prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG));
2972
 
            mm_modem_set_state (MM_MODEM (info->modem),
2973
 
                                prev_state,
2974
 
                                MM_MODEM_STATE_REASON_NONE);
2975
 
        }
 
3154
    /* Do nothing if modem removed */
 
3155
    if (!modem || mm_callback_info_check_modem_removed (info))
 
3156
        return;
 
3157
 
 
3158
    if (error) {
 
3159
        info->error = g_error_copy (error);
 
3160
        /* Reset old state since the operation failed */
 
3161
        prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG));
 
3162
        mm_modem_set_state (MM_MODEM (info->modem),
 
3163
                            prev_state,
 
3164
                            MM_MODEM_STATE_REASON_NONE);
2976
3165
    } else {
2977
3166
        MMGenericGsm *self = MM_GENERIC_GSM (modem);
2978
3167
        MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
2991
3180
                     GError *error,
2992
3181
                     gpointer user_data)
2993
3182
{
2994
 
    mm_callback_info_schedule ((MMCallbackInfo *) user_data);
 
3183
    MMCallbackInfo *info = (MMCallbackInfo *)user_data;
 
3184
 
 
3185
    /* If the modem has already been removed, return without
 
3186
     * scheduling callback */
 
3187
    if (mm_callback_info_check_modem_removed (info))
 
3188
        return;
 
3189
 
 
3190
    mm_callback_info_schedule (info);
2995
3191
}
2996
3192
 
2997
3193
static void
3023
3219
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3024
3220
    MMGenericGsmPrivate *priv;
3025
3221
 
3026
 
    info->error = mm_modem_check_removed (info->modem, error);
3027
 
    if (info->error) {
 
3222
    /* If the modem has already been removed, return without
 
3223
     * scheduling callback */
 
3224
    if (mm_callback_info_check_modem_removed (info))
 
3225
        return;
 
3226
 
 
3227
    if (error) {
3028
3228
        /* Ignore "NO CARRIER" response when modem disconnects and any flash
3029
3229
         * failures we might encounter.  Other errors are hard errors.
3030
3230
         */
3031
 
        if (   !g_error_matches (info->error, MM_MODEM_CONNECT_ERROR, MM_MODEM_CONNECT_ERROR_NO_CARRIER)
3032
 
            && !g_error_matches (info->error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_FLASH_FAILED)) {
 
3231
        if (   !g_error_matches (error, MM_MODEM_CONNECT_ERROR, MM_MODEM_CONNECT_ERROR_NO_CARRIER)
 
3232
            && !g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_FLASH_FAILED)) {
 
3233
            info->error = g_error_copy (error);
3033
3234
            mm_callback_info_schedule (info);
3034
3235
            return;
3035
3236
        }
3036
 
        g_clear_error (&info->error);
3037
3237
    }
3038
3238
 
3039
3239
    priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
3060
3260
    MMGenericGsm *self;
3061
3261
    MMGenericGsmPrivate *priv;
3062
3262
 
3063
 
    if (!info->modem) {
3064
 
        info->error = mm_modem_check_removed (info->modem, error);
3065
 
        mm_callback_info_schedule (info);
 
3263
    /* If the modem has already been removed, return without
 
3264
     * scheduling callback */
 
3265
    if (mm_callback_info_check_modem_removed (info))
3066
3266
        return;
3067
 
    }
3068
3267
 
3069
3268
    self = MM_GENERIC_GSM (info->modem);
3070
3269
    priv = MM_GENERIC_GSM_GET_PRIVATE (self);
3154
3353
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3155
3354
    GPtrArray *results;
3156
3355
 
 
3356
    /* If the modem has already been removed, return without
 
3357
     * scheduling callback */
 
3358
    if (mm_callback_info_check_modem_removed (info))
 
3359
        return;
 
3360
 
3157
3361
    if (error)
3158
3362
        info->error = g_error_copy (error);
3159
3363
    else {
3193
3397
{
3194
3398
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3195
3399
 
3196
 
    info->error = mm_modem_check_removed (info->modem, error);
3197
 
    if (!info->error) {
 
3400
    /* If the modem has already been removed, return without
 
3401
     * scheduling callback */
 
3402
    if (mm_callback_info_check_modem_removed (info))
 
3403
        return;
 
3404
 
 
3405
    if (error)
 
3406
        info->error = g_error_copy (error);
 
3407
    else {
3198
3408
        MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
3199
3409
 
3200
3410
        priv->cid = GPOINTER_TO_INT (mm_callback_info_get_data (info, APN_CID_TAG));
3212
3422
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3213
3423
    guint32 cid = 0;
3214
3424
 
 
3425
    /* If the modem has already been removed, return without
 
3426
     * scheduling callback */
 
3427
    if (mm_callback_info_check_modem_removed (info))
 
3428
        return;
 
3429
 
3215
3430
    if (error)
3216
3431
        info->error = g_error_copy (error);
3217
3432
    else if (g_str_has_prefix (response->str, "+CGDCONT:")) {
3278
3493
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3279
3494
    gboolean found = FALSE;
3280
3495
 
3281
 
    info->error = mm_modem_check_removed (info->modem, error);
3282
 
    if (info->error)
3283
 
        goto done;
3284
 
    else if (g_str_has_prefix (response->str, "+CGDCONT:")) {
 
3496
    /* If the modem has already been removed, return without
 
3497
     * scheduling callback */
 
3498
    if (mm_callback_info_check_modem_removed (info))
 
3499
        return;
 
3500
 
 
3501
    if (error) {
 
3502
        info->error = g_error_copy (error);
 
3503
    } else if (g_str_has_prefix (response->str, "+CGDCONT:")) {
3285
3504
        GRegex *r;
3286
3505
        GMatchInfo *match_info;
3287
3506
 
3332
3551
                                           MM_MODEM_ERROR_GENERAL,
3333
3552
                                           "Could not parse the response");
3334
3553
 
3335
 
done:
3336
3554
    if (found || info->error)
3337
3555
        mm_callback_info_schedule (info);
3338
3556
    else {
3439
3657
    GByteArray *indicators;
3440
3658
    guint quality;
3441
3659
 
3442
 
    info->error = mm_modem_check_removed (info->modem, error);
3443
 
    if (!info->error) {
 
3660
    /* If the modem has already been removed, return without
 
3661
     * scheduling callback */
 
3662
    if (mm_callback_info_check_modem_removed (info))
 
3663
        return;
 
3664
 
 
3665
    if (error)
 
3666
        info->error = g_error_copy (error);
 
3667
    else {
3444
3668
        priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
3445
3669
 
3446
3670
        indicators = mm_parse_cind_query_response (response->str, &info->error);
3468
3692
    char *reply = response->str;
3469
3693
    gboolean parsed = FALSE;
3470
3694
 
3471
 
    info->error = mm_modem_check_removed (info->modem, error);
3472
 
    if (info->error)
 
3695
    /* If the modem has already been removed, return without
 
3696
     * scheduling callback */
 
3697
    if (mm_callback_info_check_modem_removed (info))
 
3698
        return;
 
3699
 
 
3700
    if (error) {
 
3701
        info->error = g_error_copy (error);
3473
3702
        goto done;
 
3703
    }
3474
3704
 
3475
3705
    if (!strncmp (reply, "+CSQ: ", 6)) {
3476
3706
        /* Got valid reply */
3618
3848
{
3619
3849
    MMCallbackInfo *info = user_data;
3620
3850
 
3621
 
    info->error = mm_modem_check_removed (info->modem, error);
3622
 
    if (!info->error) {
 
3851
    /* Do nothing if modem removed */
 
3852
    if (!modem || mm_callback_info_check_modem_removed (info))
 
3853
        return;
 
3854
 
 
3855
    if (error)
 
3856
        info->error = g_error_copy (error);
 
3857
    else {
3623
3858
        MMModemGsmAllowedMode mode = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mode"));
3624
3859
 
3625
3860
        mm_generic_gsm_update_allowed_mode (MM_GENERIC_GSM (info->modem), mode);
3674
3909
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3675
3910
    MMGenericGsmPrivate *priv;
3676
3911
 
3677
 
    info->error = mm_modem_check_removed (info->modem, error);
3678
 
    if (info->error) {
 
3912
    /* If the modem has already been removed, return without
 
3913
     * scheduling callback */
 
3914
    if (mm_callback_info_check_modem_removed (info))
 
3915
        return;
 
3916
 
 
3917
    if (error) {
 
3918
        info->error = g_error_copy (error);
3679
3919
        mm_callback_info_schedule (info);
3680
3920
        return;
3681
3921
    }
3733
3973
    MMModemCharset tried_charset;
3734
3974
    const char *p;
3735
3975
 
3736
 
    info->error = mm_modem_check_removed (info->modem, error);
3737
 
    if (info->error) {
 
3976
    /* If the modem has already been removed, return without
 
3977
     * scheduling callback */
 
3978
    if (mm_callback_info_check_modem_removed (info))
 
3979
        return;
 
3980
 
 
3981
    if (error) {
 
3982
        info->error = g_error_copy (error);
3738
3983
        mm_callback_info_schedule (info);
3739
3984
        return;
3740
3985
    }
3770
4015
{
3771
4016
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3772
4017
 
3773
 
    info->error = mm_modem_check_removed (info->modem, error);
3774
 
    if (info->error) {
 
4018
    /* If the modem has already been removed, return without
 
4019
     * scheduling callback */
 
4020
    if (mm_callback_info_check_modem_removed (info))
 
4021
        return;
 
4022
 
 
4023
    if (error) {
3775
4024
        gboolean tried_no_quotes = !!mm_callback_info_get_data (info, TRIED_NO_QUOTES_TAG);
3776
4025
        MMModemCharset charset = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "charset"));
3777
4026
        char *command;
3778
4027
 
3779
 
        if (!info->modem || tried_no_quotes) {
 
4028
        if (tried_no_quotes) {
 
4029
            info->error = g_error_copy (error);
3780
4030
            mm_callback_info_schedule (info);
3781
4031
            return;
3782
4032
        }
3856
4106
#define  SMS_TP_MTI_SMS_SUBMIT_REPORT 0x01
3857
4107
#define  SMS_TP_MTI_SMS_STATUS_REPORT 0x02
3858
4108
 
 
4109
#define SMS_NUMBER_TYPE_MASK          0x70
 
4110
#define SMS_NUMBER_TYPE_UNKNOWN       0x00
 
4111
#define SMS_NUMBER_TYPE_INTL          0x10
 
4112
#define SMS_NUMBER_TYPE_ALPHA         0x50
 
4113
 
 
4114
#define SMS_NUMBER_PLAN_MASK          0x0f
 
4115
#define SMS_NUMBER_PLAN_TELEPHONE     0x01
 
4116
 
3859
4117
#define SMS_TP_MMS                    0x04
3860
4118
#define SMS_TP_SRI                    0x20
3861
4119
#define SMS_TP_UDHI                   0x40
3881
4139
{
3882
4140
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
3883
4141
 
 
4142
    /* If the modem has already been removed, return without
 
4143
     * scheduling callback */
 
4144
    if (mm_callback_info_check_modem_removed (info))
 
4145
        return;
 
4146
 
3884
4147
    if (error)
3885
4148
        info->error = g_error_copy (error);
3886
4149
 
3931
4194
    *dest++ = '\0';
3932
4195
}
3933
4196
 
3934
 
/* len is in septets for gsm7 and in digits (semi-octets) for others */
 
4197
/* len is in semi-octets */
3935
4198
static char *
3936
4199
sms_decode_address (const guint8 *address, int len)
3937
4200
{
3938
 
    guint8 addrtype;
 
4201
    guint8 addrtype, addrplan;
3939
4202
    char *utf8;
3940
4203
 
3941
 
    addrtype = address[0];
 
4204
    addrtype = address[0] & SMS_NUMBER_TYPE_MASK;
 
4205
    addrplan = address[0] & SMS_NUMBER_PLAN_MASK;
3942
4206
    address++;
3943
4207
 
3944
 
    if (addrtype == 0xd0) {
 
4208
    if (addrtype == SMS_NUMBER_TYPE_ALPHA) {
3945
4209
        guint8 *unpacked;
3946
4210
        guint32 unpacked_len;
3947
 
        unpacked = gsm_unpack (address + 1, len, 0, &unpacked_len);
 
4211
        unpacked = gsm_unpack (address, (len * 4) / 7, 0, &unpacked_len);
3948
4212
        utf8 = (char *)mm_charset_gsm_unpacked_to_utf8 (unpacked,
3949
4213
                                                        unpacked_len);
3950
4214
        g_free(unpacked);
 
4215
    } else if (addrtype == SMS_NUMBER_TYPE_INTL &&
 
4216
               addrplan == SMS_NUMBER_PLAN_TELEPHONE) {
 
4217
        /* International telphone number, format as "+1234567890" */
 
4218
        utf8 = g_malloc (len + 3); /* '+' + digits + possible trailing 0xf + NUL */
 
4219
        utf8[0] = '+';
 
4220
        sms_semi_octets_to_bcd_string (utf8 + 1, address, (len + 1) / 2);
3951
4221
    } else {
3952
 
        utf8 = g_malloc (len + 2); /* may need one extra for trailing 0xf */
 
4222
        /*
 
4223
         * All non-alphanumeric types and plans are just digits, but
 
4224
         * don't apply any special formatting if we don't know the
 
4225
         * format.
 
4226
         */
 
4227
        utf8 = g_malloc (len + 2); /* digits + possible trailing 0xf + NUL */
3953
4228
        sms_semi_octets_to_bcd_string (utf8, address, (len + 1) / 2);
3954
4229
    }
3955
4230
 
4071
4346
        return NULL;
4072
4347
    }
4073
4348
 
4074
 
    /* Only handle the basic protocol identifier */
4075
 
    if (pdu[tp_pid_offset] != 0) {
4076
 
        mm_err ("Unhandled protocol identifier: 0x%02x vs 0x00",
4077
 
                pdu[tp_pid_offset]);
4078
 
        g_free (pdu);
4079
 
        return NULL;
4080
 
    }
4081
 
 
4082
4349
    smsc_addr = sms_decode_address (&pdu[1], 2 * (pdu[0] - 1));
4083
4350
    sender_addr = sms_decode_address (&pdu[msg_start_offset + 2],
4084
4351
                                      pdu[msg_start_offset + 1]);
4138
4405
    int rv, status, tpdu_len, offset;
4139
4406
    char pdu[SMS_MAX_PDU_LEN + 1];
4140
4407
 
 
4408
    /* If the modem has already been removed, return without
 
4409
     * scheduling callback */
 
4410
    if (mm_callback_info_check_modem_removed (info))
 
4411
        return;
 
4412
 
4141
4413
    if (error) {
4142
4414
        info->error = g_error_copy (error);
4143
4415
        goto out;
4212
4484
{
4213
4485
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
4214
4486
 
 
4487
    /* If the modem has already been removed, return without
 
4488
     * scheduling callback */
 
4489
    if (mm_callback_info_check_modem_removed (info))
 
4490
        return;
 
4491
 
4215
4492
    if (error)
4216
4493
        info->error = g_error_copy (error);
4217
4494
 
4227
4504
    MMCallbackInfo *info;
4228
4505
    char *command;
4229
4506
    MMAtSerialPort *port;
 
4507
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (MM_GENERIC_GSM (modem));
4230
4508
 
4231
4509
    info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
 
4510
    g_hash_table_remove (priv->sms_present, GINT_TO_POINTER (idx));
4232
4511
 
4233
4512
    port = mm_generic_gsm_get_best_at_port (MM_GENERIC_GSM (modem), &info->error);
4234
4513
    if (!port) {
4251
4530
    int rv, status, tpdu_len, offset;
4252
4531
    char *rstr;
4253
4532
 
 
4533
    /* If the modem has already been removed, return without
 
4534
     * scheduling callback */
 
4535
    if (mm_callback_info_check_modem_removed (info))
 
4536
        return;
 
4537
 
4254
4538
    if (error)
4255
4539
        info->error = g_error_copy (error);
4256
4540
    else {
4389
4673
    const char *str, *start = NULL, *end = NULL;
4390
4674
    char *reply = NULL, *converted;
4391
4675
 
 
4676
    /* If the modem has already been removed, return without
 
4677
     * scheduling callback */
 
4678
    if (mm_callback_info_check_modem_removed (info))
 
4679
        return;
 
4680
 
4392
4681
    if (error) {
4393
4682
        info->error = g_error_copy (error);
4394
4683
        goto done;
4471
4760
    GByteArray *ussd_command = g_byte_array_new();
4472
4761
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
4473
4762
    MMAtSerialPort *port;
 
4763
    gboolean success;
4474
4764
 
4475
4765
    info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
4476
4766
 
4481
4771
    }
4482
4772
 
4483
4773
    /* encode to cur_charset */
4484
 
    g_warn_if_fail (mm_modem_charset_byte_array_append (ussd_command, command, FALSE, priv->cur_charset));
 
4774
    success = mm_modem_charset_byte_array_append (ussd_command, command, FALSE, priv->cur_charset);
 
4775
    g_warn_if_fail (success == TRUE);
 
4776
 
4485
4777
    /* convert to hex representation */
4486
4778
    hex = utils_bin2hexstr (ussd_command->data, ussd_command->len);
4487
4779
    g_byte_array_free (ussd_command, TRUE);
4502
4794
{
4503
4795
    MMCallbackInfo *info;
4504
4796
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
 
4797
 
4505
4798
    info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
4506
4799
 
4507
4800
    if (priv->ussd_state != MM_MODEM_GSM_USSD_STATE_IDLE) {
4509
4802
                                   MM_MODEM_ERROR_GENERAL,
4510
4803
                                   "USSD session already active.");
4511
4804
        mm_callback_info_schedule (info);
4512
 
        return;
 
4805
    } else {
 
4806
        ussd_send (modem, command, callback, user_data);
4513
4807
    }
4514
 
 
4515
 
    ussd_send (modem, command, callback, user_data);
4516
 
    return;
4517
4808
}
4518
4809
 
4519
4810
static void
4524
4815
{
4525
4816
    MMCallbackInfo *info;
4526
4817
    MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
 
4818
 
4527
4819
    info = mm_callback_info_string_new (MM_MODEM (modem), callback, user_data);
4528
4820
 
4529
4821
    if (priv->ussd_state != MM_MODEM_GSM_USSD_STATE_USER_RESPONSE) {
4531
4823
                                   MM_MODEM_ERROR_GENERAL,
4532
4824
                                   "No active USSD session, cannot respond.");
4533
4825
        mm_callback_info_schedule (info);
4534
 
        return;
 
4826
    } else {
 
4827
        ussd_send (modem, command, callback, user_data);
4535
4828
    }
4536
 
 
4537
 
    ussd_send (modem, command, callback, user_data);
4538
 
    return;
4539
4829
}
4540
4830
 
4541
4831
static void
4546
4836
{
4547
4837
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
4548
4838
 
 
4839
    /* If the modem has already been removed, return without
 
4840
     * scheduling callback */
 
4841
    if (mm_callback_info_check_modem_removed (info))
 
4842
        return;
 
4843
 
4549
4844
    if (error)
4550
4845
        info->error = g_error_copy (error);
4551
4846
 
4552
4847
    mm_callback_info_schedule (info);
4553
4848
 
4554
 
    if (info->modem)
4555
 
        ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE);
 
4849
    ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE);
4556
4850
}
4557
4851
 
4558
4852
static void
4710
5004
    gboolean home_only = FALSE;
4711
5005
    char *data_device;
4712
5006
 
4713
 
    info->error = mm_modem_check_removed (modem, error);
4714
 
    if (info->error)
 
5007
    /* Do nothing if modem removed */
 
5008
    if (!modem || mm_callback_info_check_modem_removed (info))
 
5009
        return;
 
5010
 
 
5011
    if (error) {
 
5012
        info->error = g_error_copy (error);
4715
5013
        goto out;
 
5014
    }
4716
5015
 
4717
5016
    priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
4718
5017
 
4929
5228
    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
4930
5229
    GHashTable *properties;
4931
5230
 
4932
 
    info->error = mm_modem_check_removed ((MMModem *) modem, error);
4933
 
    if (!info->error) {
 
5231
    /* Do nothing if modem removed */
 
5232
    if (!modem || mm_callback_info_check_modem_removed (info))
 
5233
        return;
 
5234
 
 
5235
    if (error)
 
5236
        info->error = g_error_copy (error);
 
5237
    else {
4934
5238
        properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG);
4935
5239
 
4936
5240
        g_hash_table_insert (properties, "registration_status", simple_uint_value (status));
5188
5492
    class->get_imei = get_imei;
5189
5493
    class->get_imsi = get_imsi;
5190
5494
    class->get_operator_id = get_operator_id;
 
5495
    class->get_spn = get_spn;
5191
5496
    class->send_pin = send_pin;
5192
5497
    class->send_puk = send_puk;
5193
5498
    class->enable_pin = enable_pin;
5238
5543
    priv->act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
5239
5544
    priv->reg_regex = mm_gsm_creg_regex_get (TRUE);
5240
5545
    priv->roam_allowed = TRUE;
 
5546
    priv->sms_present = g_hash_table_new (g_direct_hash, g_direct_equal);
5241
5547
 
5242
5548
    mm_properties_changed_signal_register_property (G_OBJECT (self),
5243
5549
                                                    MM_MODEM_GSM_NETWORK_ALLOWED_MODE,
5455
5761
    g_free (priv->oper_code);
5456
5762
    g_free (priv->oper_name);
5457
5763
    g_free (priv->simid);
 
5764
    g_hash_table_destroy (priv->sms_present);
5458
5765
 
5459
5766
    G_OBJECT_CLASS (mm_generic_gsm_parent_class)->finalize (object);
5460
5767
}