ModemManager: [PATCH 2/2] Improvements to SIM PIN handling




From b129d263ec1674462c218b4ec91260cf082bf77e Mon Sep 17 00:00:00 2001
From: Eric Shienbrood <ers google com>
Date: Thu, 11 Aug 2011 13:58:59 -0400
Subject: [PATCH] Added new property to track which facility locks are enabled.

The property EnabledFacilityLocks on the .Modem.Gsm.Card interface
is a bit mask that indicates which of the various personalization
codes from 3GPP TS 22.022, plus the SIM PIN lock and SIM PIN2 lock,
are enabled. The set of facility locks supported by the modem is
determined at the time the modem is initialized, and the state of
each supported lock (enabled or disabled) is determined. When the
state of a lock changes, a property-change signal is sent out. Note
that ModemManager only supports enabling and disabling SIM-PIN, via
the EnablePin method on Modem.Gsm.Card.
---
 ...org.freedesktop.ModemManager.Modem.Gsm.Card.xml |    6 +
 .../org.freedesktop.ModemManager.Modem.Gsm.xml     |   37 ++++-
 src/mm-generic-gsm.c                               |  186 +++++++++++++++++---
 src/mm-generic-gsm.h                               |    3 +-
 src/mm-modem-gsm-card.c                            |   10 +
 src/mm-modem-gsm-card.h                            |    3 +
 src/mm-modem-helpers.c                             |  145 +++++++++++++++
 src/mm-modem-helpers.h                             |    7 +
 8 files changed, 369 insertions(+), 28 deletions(-)

diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml
index 03c8a9f..9159052 100644
--- a/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml
@@ -144,5 +144,11 @@
       </tp:docstring>
     </property>
 
+    <property name="EnabledFacilityLocks" type="u" access="read" tp:type="MM_MODEM_GSM_FACILITY">
+      <tp:docstring>
+        Facilities for which PIN locking is enabled.
+      </tp:docstring>
+    </property>
+
   </interface>
 </node>
diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml
index 1abf915..354ce4a 100644
--- a/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml
+++ b/introspection/org.freedesktop.ModemManager.Modem.Gsm.xml
@@ -4,7 +4,7 @@
   <interface name="org.freedesktop.ModemManager.Modem.Gsm">
     <tp:flags name="MM_MODEM_GSM_MODE" value-prefix="MM_MODEM_GSM_MODE" type="u">
       <tp:docstring>
-        A bitfield describing the specifc access modes and technologies
+        A bitfield describing the specific access modes and technologies
         supported by a device and the access technology in-use when connected to
         a mobile network.
       </tp:docstring>
@@ -168,6 +168,41 @@
       </tp:enumvalue>
     </tp:enum>
 
+    <tp:flags name="MM_MODEM_GSM_FACILITY" value-prefix="MM_MODEM_GSM_FACILITY" type="u">
+      <tp:docstring>
+        A bitfield describing which facilities have a lock enabled, i.e.,
+        requires a pin or unlock code. The facilities include the
+        personalizations (device locks) described in 3GPP spec TS 22.022,
+        and the PIN and PIN2 locks, which are SIM locks.
+      </tp:docstring>
+      <tp:flag suffix="NONE" value="0x0">
+        <tp:docstring>No facility</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="SIM" value="0x1">
+        <tp:docstring>SIM lock</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="FIXED_DIALING" value="0x2">
+        <tp:docstring>Fixed dialing (PIN2) SIM lock</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="PH_SIM" value="0x4">
+        <tp:docstring>Device is locked to a specific SIM</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="PH_FSIM" value="0x8">
+        <tp:docstring>Device is locked to first SIM inserted</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="NET_PERS" value="0x10">
+        <tp:docstring>Network personalization</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="NET_SUB_PERS" value="0x20">
+        <tp:docstring>Network subset personalization</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="PROVIDER_PERS" value="0x40">
+        <tp:docstring>Service provider personalization</tp:docstring>
+      </tp:flag>
+      <tp:flag suffix="CORP_PERS" value="0x80">
+        <tp:docstring>Corporate personalization</tp:docstring>
+      </tp:flag>
+    </tp:flags>
   </interface>
 </node>
 
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index 82dcf00..36490f4 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -129,6 +129,13 @@ typedef struct {
 
     /* SMS */
     GHashTable *sms_present;
+
+    /* Facility locks */
+    MMModemGsmFacility supported_facilities;
+    MMModemGsmFacility enabled_facilities;
+    MMModemGsmFacility pending_facility;
+    gboolean pending_facility_enable;
+    guint facilities_idx;
 } MMGenericGsmPrivate;
 
 static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info);
@@ -799,6 +806,29 @@ initial_info_check (MMGenericGsm *self)
     }
 }
 
+static void clck_cb (MMAtSerialPort *port, GString *response, GError *error, gpointer user_data);
+
+static void
+initial_facility_lock_check (MMGenericGsm *self) {
+    GError *error = NULL;
+    MMGenericGsmPrivate *priv;
+
+    g_return_if_fail (MM_IS_GENERIC_GSM (self));
+    priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+    g_return_if_fail (priv->primary != NULL);
+
+    if (mm_serial_port_open (MM_SERIAL_PORT (priv->primary), &error)) {
+        mm_at_serial_port_queue_command (priv->primary, "+CLCK=?", 3, clck_cb, self);
+    } else {
+        g_warning ("%s: failed to open serial port: (%d) %s",
+                   __func__,
+                   error ? error->code : -1,
+                   error && error->message ? error->message : "(unknown)");
+        g_clear_error (&error);
+    }
+}
+
 static gboolean
 owns_port (MMModem *modem, const char *subsys, const char *name)
 {
@@ -872,6 +902,9 @@ mm_generic_gsm_grab_port (MMGenericGsm *self,
              */
             initial_pin_check (self);
 
+            /* Determine what facility locks are supported */
+            initial_facility_lock_check (self);
+
         } else if (ptype == MM_PORT_TYPE_SECONDARY)
             priv->secondary = MM_AT_SERIAL_PORT (port);
     } else if (MM_IS_QCDM_SERIAL_PORT (port)) {
@@ -1437,6 +1470,91 @@ cusd_enable_cb (MMAtSerialPort *port,
     MM_GENERIC_GSM_GET_PRIVATE (user_data)->ussd_enabled = TRUE;
 }
 
+static void get_facility_lock_state (MMAtSerialPort *port, MMGenericGsm *self);
+
+static void
+get_facility_lock_state_done (MMAtSerialPort *port,
+                              GString *response,
+                              GError *error,
+                              gpointer user_data)
+{
+    MMGenericGsm *self;
+    MMGenericGsmPrivate *priv;
+    gboolean enabled = FALSE;
+
+    if (error)
+        return;
+
+    self = MM_GENERIC_GSM (user_data);
+    priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+    if (mm_gsm_parse_clck_response (response->str, &enabled)) {
+        if (enabled)
+            priv->enabled_facilities |= priv->pending_facility;
+        else
+            priv->enabled_facilities &= ~priv->pending_facility;
+    }
+    priv->pending_facility = MM_MODEM_GSM_FACILITY_NONE;
+    ++priv->facilities_idx;
+    /* Get the state of the next facility */
+    get_facility_lock_state (port, self);
+}
+
+static void
+get_facility_lock_state (MMAtSerialPort *port, MMGenericGsm *self)
+{
+    MMModemGsmFacility found = MM_MODEM_GSM_FACILITY_NONE;
+    gchar *cmd;
+    MMGenericGsmPrivate *priv;
+    gchar *facility_name;
+
+    priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+    while (priv->facilities_idx < sizeof (MMModemGsmFacility)*8) {
+        guint32 facility = 1 << priv->facilities_idx;
+        if (priv->supported_facilities & facility) {
+            found = facility;
+            break;
+        }
+        ++priv->facilities_idx;
+    }
+    if (found != MM_MODEM_GSM_FACILITY_NONE) {
+        facility_name = mm_gsm_get_facility_name (found);
+        if (facility_name != NULL) {
+            priv->pending_facility = found;
+            cmd = g_strdup_printf ("+CLCK=\"%s\",2", facility_name);
+            mm_at_serial_port_queue_command (port, cmd, 3, get_facility_lock_state_done, self);
+            g_free (cmd);
+            return;
+        }
+    }
+    mm_serial_port_close (MM_SERIAL_PORT (port));
+}
+
+static void
+clck_cb (MMAtSerialPort *port,
+         GString *response,
+         GError *error,
+         gpointer user_data)
+{
+    MMGenericGsm *self;
+    MMGenericGsmPrivate *priv;
+    MMModemGsmFacility facilities;
+
+    if (error)
+        return;
+
+    self = MM_GENERIC_GSM (user_data);
+    priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+    if (mm_gsm_parse_clck_test_response (response->str, &facilities)) {
+        priv->supported_facilities = facilities;
+        priv->facilities_idx = 0;
+        get_facility_lock_state (port, self);
+    } else {
+        mm_serial_port_close (MM_SERIAL_PORT (port));
+    }
+}
+
 void
 mm_generic_gsm_enable_complete (MMGenericGsm *self,
                                 GError *error,
@@ -2227,22 +2345,25 @@ pin_puk_recheck_done (MMModem *modem, GError *error, gpointer user_data)
  * if an incorrect PIN was supplied. Check also for a SIM_PUK
  * error, which occurs if PIN retries has reached zero. */
 static void
-update_pin_puk_status(MMCallbackInfo *info, GError *error)
+update_pin_puk_status (MMModem *modem, GError *error)
 {
+    /* Hard-wire to SIM-PIN, because that's the only
+     * lock that ChangePin and EnablePin are defined
+     * to operate on */
     const char *pin_type = "sim-pin";
 
     if (error) {
         if (error->domain != MM_MOBILE_ERROR)
             return;
         if (error->code == MM_MOBILE_ERROR_SIM_PUK) {
-            mm_modem_base_set_unlock_required (MM_MODEM_BASE (info->modem),
+            mm_modem_base_set_unlock_required (MM_MODEM_BASE (modem),
                                                "sim-puk");
             pin_type = "sim-puk";
         } else if (error->code != MM_MOBILE_ERROR_WRONG_PASSWORD) {
             return;
         }
     }
-    mm_modem_gsm_card_get_unlock_retries (MM_MODEM_GSM_CARD (info->modem),
+    mm_modem_gsm_card_get_unlock_retries (MM_MODEM_GSM_CARD (modem),
                                           pin_type,
                                           get_unlock_retries_cb,
                                           NULL);
@@ -2386,19 +2507,36 @@ send_pin (MMModemGsmCard *modem,
 }
 
 static void
-enable_pin_done (MMAtSerialPort *port,
+pin_operation_done (MMAtSerialPort *port,
                  GString *response,
                  GError *error,
                  gpointer user_data)
 {
     MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+    MMGenericGsmPrivate *priv;
+    MMModem *modem;
 
     /* If the modem has already been removed, return without
      * scheduling callback */
     if (mm_callback_info_check_modem_removed (info))
         return;
 
-    update_pin_puk_status(info, error);
+    modem = info->modem;
+    priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
+    if (!error) {
+        if (priv->pending_facility != MM_MODEM_GSM_FACILITY_NONE) {
+            MMModemGsmFacility old = priv->enabled_facilities;
+            if (priv->pending_facility_enable)
+                priv->enabled_facilities |= priv->pending_facility;
+            else
+                priv->enabled_facilities &= ~priv->pending_facility;
+            if (priv->enabled_facilities != old)
+                g_object_notify (G_OBJECT (modem),
+                                 MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS);
+        }
+    }
+    priv->pending_facility = MM_MODEM_GSM_FACILITY_NONE;
+    update_pin_puk_status (modem, error);
     if (error)
         info->error = g_error_copy (error);
     mm_callback_info_schedule (info);
@@ -2417,30 +2555,13 @@ enable_pin (MMModemGsmCard *modem,
 
     info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
     command = g_strdup_printf ("+CLCK=\"SC\",%d,\"%s\"", enabled ? 1 : 0, pin);
-    mm_at_serial_port_queue_command (priv->primary, command, 3, enable_pin_done, info);
+    priv->pending_facility = MM_MODEM_GSM_FACILITY_SIM;
+    priv->pending_facility_enable = enabled;
+    mm_at_serial_port_queue_command (priv->primary, command, 3, pin_operation_done, info);
     g_free (command);
 }
 
 static void
-change_pin_done (MMAtSerialPort *port,
-                 GString *response,
-                 GError *error,
-                 gpointer user_data)
-{
-    MMCallbackInfo *info = (MMCallbackInfo *) user_data;
-
-    /* If the modem has already been removed, return without
-     * scheduling callback */
-    if (mm_callback_info_check_modem_removed (info))
-        return;
-
-    update_pin_puk_status(info, error);
-    if (error)
-        info->error = g_error_copy (error);
-    mm_callback_info_schedule (info);
-}
-
-static void
 change_pin (MMModemGsmCard *modem,
             const char *old_pin,
             const char *new_pin,
@@ -2453,7 +2574,7 @@ change_pin (MMModemGsmCard *modem,
 
     info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
     command = g_strdup_printf ("+CPWD=\"SC\",\"%s\",\"%s\"", old_pin, new_pin);
-    mm_at_serial_port_queue_command (priv->primary, command, 3, change_pin_done, info);
+    mm_at_serial_port_queue_command (priv->primary, command, 3, pin_operation_done, info);
     g_free (command);
 }
 
@@ -5622,6 +5743,11 @@ mm_generic_gsm_init (MMGenericGsm *self)
                                                     MM_MODEM_GSM_NETWORK_DBUS_INTERFACE);
 
     mm_properties_changed_signal_register_property (G_OBJECT (self),
+                                                    MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS,
+                                                    NULL,
+                                                    MM_MODEM_GSM_CARD_DBUS_INTERFACE);
+
+    mm_properties_changed_signal_register_property (G_OBJECT (self),
                                                     MM_MODEM_LOCATION_CAPABILITIES,
                                                     "Capabilities",
                                                     MM_MODEM_LOCATION_DBUS_INTERFACE);
@@ -5675,6 +5801,7 @@ set_property (GObject *object, guint prop_id,
     case MM_GENERIC_GSM_PROP_ALLOWED_MODE:
     case MM_GENERIC_GSM_PROP_ACCESS_TECHNOLOGY:
     case MM_GENERIC_GSM_PROP_SIM_IDENTIFIER:
+    case MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS:
     case MM_GENERIC_GSM_PROP_LOC_CAPABILITIES:
     case MM_GENERIC_GSM_PROP_LOC_ENABLED:
     case MM_GENERIC_GSM_PROP_LOC_SIGNAL:
@@ -5765,6 +5892,9 @@ get_property (GObject *object, guint prop_id,
     case MM_GENERIC_GSM_PROP_SIM_IDENTIFIER:
         g_value_set_string (value, priv->simid);
         break;
+    case MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS:
+        g_value_set_uint (value, priv->enabled_facilities);
+        break;
     case MM_GENERIC_GSM_PROP_LOC_CAPABILITIES:
         g_value_set_uint (value, priv->loc_caps);
         break;
@@ -5883,6 +6013,10 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass)
                                       MM_MODEM_GSM_CARD_SUPPORTED_MODES);
 
     g_object_class_override_property (object_class,
+                                      MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS,
+                                      MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS);
+
+    g_object_class_override_property (object_class,
                                       MM_GENERIC_GSM_PROP_ALLOWED_MODE,
                                       MM_MODEM_GSM_NETWORK_ALLOWED_MODE);
 
diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h
index 7fba1f3..bbf7988 100644
--- a/src/mm-generic-gsm.h
+++ b/src/mm-generic-gsm.h
@@ -64,7 +64,8 @@ typedef enum {
     MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD,
     MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD,
     MM_GENERIC_GSM_PROP_SMS_STORAGE_LOCATION_CMD,
-    MM_GENERIC_GSM_PROP_CMER_ENABLE_CMD
+    MM_GENERIC_GSM_PROP_CMER_ENABLE_CMD,
+    MM_GENERIC_GSM_PROP_ENABLED_FACILITY_LOCKS
 } MMGenericGsmProp;
 
 typedef enum {
diff --git a/src/mm-modem-gsm-card.c b/src/mm-modem-gsm-card.c
index 9b1fd77..8c4cf1c 100644
--- a/src/mm-modem-gsm-card.c
+++ b/src/mm-modem-gsm-card.c
@@ -661,6 +661,16 @@ mm_modem_gsm_card_init (gpointer g_iface)
                             G_MAXUINT32,
                             MM_MODEM_GSM_MODE_UNKNOWN,
                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_interface_install_property
+        (g_iface,
+         g_param_spec_uint (MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS,
+                            "Enabled Facility Locks",
+                            "Facility locks (i.e. PINs) that are enabled",
+                            MM_MODEM_GSM_FACILITY_NONE,
+                            G_MAXUINT32,
+                            MM_MODEM_GSM_FACILITY_NONE,
+                            G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 GType
diff --git a/src/mm-modem-gsm-card.h b/src/mm-modem-gsm-card.h
index 9716bf7..bee9000 100644
--- a/src/mm-modem-gsm-card.h
+++ b/src/mm-modem-gsm-card.h
@@ -19,6 +19,8 @@
 
 #include <mm-modem.h>
 
+#define MM_MODEM_GSM_CARD_DBUS_INTERFACE "org.freedesktop.ModemManager.Modem.Gsm.Card"
+
 #define MM_TYPE_MODEM_GSM_CARD      (mm_modem_gsm_card_get_type ())
 #define MM_MODEM_GSM_CARD(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_MODEM_GSM_CARD, MMModemGsmCard))
 #define MM_IS_MODEM_GSM_CARD(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_MODEM_GSM_CARD))
@@ -27,6 +29,7 @@
 #define MM_MODEM_GSM_CARD_SUPPORTED_BANDS "supported-bands"
 #define MM_MODEM_GSM_CARD_SUPPORTED_MODES "supported-modes"
 #define MM_MODEM_GSM_CARD_SIM_IDENTIFIER  "sim-identifier"
+#define MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS  "enabled-facility-locks"
 
 #define MM_MODEM_GSM_CARD_SIM_PIN "sim-pin"
 #define MM_MODEM_GSM_CARD_SIM_PIN2 "sim-pin2"
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index 66c3fb6..652aadb 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -788,6 +788,151 @@ mm_gsm_parse_cscs_support_response (const char *reply,
 
 /*************************************************************************/
 
+/* Map two letter facility codes into flag values. There are
+ * many more facilities defined (for various flavors of call
+ * barring); we only map the ones we care about. */
+static MMModemGsmFacility
+mm_gsm_string_to_facility (const char *string)
+{
+    g_return_val_if_fail (string != NULL, MM_MODEM_GSM_FACILITY_NONE);
+
+    if (!strcmp(string, "SC"))
+        return MM_MODEM_GSM_FACILITY_SIM;
+    else if (!strcmp(string, "PS"))
+        return MM_MODEM_GSM_FACILITY_PH_SIM;
+    else if (!strcmp(string, "PF"))
+        return MM_MODEM_GSM_FACILITY_PH_FSIM;
+    else if (!strcmp(string, "FD"))
+        return MM_MODEM_GSM_FACILITY_FIXED_DIALING;
+    else if (!strcmp(string, "PN"))
+        return MM_MODEM_GSM_FACILITY_NET_PERS;
+    else if (!strcmp(string, "PU"))
+        return MM_MODEM_GSM_FACILITY_NET_SUB_PERS;
+    else if (!strcmp(string, "PP"))
+        return MM_MODEM_GSM_FACILITY_PROVIDER_PERS;
+    else if (!strcmp(string, "PC"))
+        return MM_MODEM_GSM_FACILITY_CORP_PERS;
+    else
+        return MM_MODEM_GSM_FACILITY_NONE;
+
+}
+
+/*************************************************************************/
+
+char *
+mm_gsm_get_facility_name(MMModemGsmFacility facility)
+{
+    switch (facility) {
+    case MM_MODEM_GSM_FACILITY_SIM:
+        return "SC";
+    case MM_MODEM_GSM_FACILITY_PH_SIM:
+        return "PS";
+    case MM_MODEM_GSM_FACILITY_PH_FSIM:
+        return "PF";
+    case MM_MODEM_GSM_FACILITY_FIXED_DIALING:
+        return "FD";
+    case MM_MODEM_GSM_FACILITY_NET_PERS:
+        return "PN";
+    case MM_MODEM_GSM_FACILITY_NET_SUB_PERS:
+        return "PU";
+    case MM_MODEM_GSM_FACILITY_PROVIDER_PERS:
+        return "PP";
+    case MM_MODEM_GSM_FACILITY_CORP_PERS:
+        return "PC";
+    default:
+        return NULL;
+    }
+}
+
+gboolean
+mm_gsm_parse_clck_test_response (const char *reply,
+                                 MMModemGsmFacility *out_facilities)
+{
+    MMModemGsmFacility facilities = MM_MODEM_GSM_FACILITY_NONE;
+    GRegex *r;
+    GMatchInfo *match_info;
+    char *p, *str;
+    gboolean success = FALSE;
+
+    g_return_val_if_fail (reply != NULL, FALSE);
+    g_return_val_if_fail (out_facilities != NULL, FALSE);
+
+    /* the general format is:
+     *
+     * +CLCK: ("SC","AO","AI","PN")
+     */
+    p = strchr (reply, '(');
+    if (p)
+        p++;
+    else {
+        p = strchr (reply, '"');
+        if (!p)
+            return FALSE;
+    }
+
+    /* Now parse each facility */
+    r = g_regex_new ("\\s*\"([^,\\)]+)\"\\s*", 0, 0, NULL);
+    if (!r)
+        return FALSE;
+
+    if (g_regex_match_full (r, p, strlen (p), 0, 0, &match_info, NULL)) {
+        while (g_match_info_matches (match_info)) {
+            str = g_match_info_fetch (match_info, 1);
+            if (str)
+                facilities |= mm_gsm_string_to_facility (str);
+            g_free (str);
+
+            g_match_info_next (match_info, NULL);
+            success = TRUE;
+        }
+    }
+    g_match_info_free (match_info);
+    g_regex_unref (r);
+
+    if (success)
+        *out_facilities = facilities;
+
+    return success;
+}
+
+gboolean
+mm_gsm_parse_clck_response (const char *reply, gboolean *enabled)
+{
+    GRegex *r;
+    GMatchInfo *match_info;
+    char *p, *str;
+    gboolean success = FALSE;
+
+    g_return_val_if_fail (reply != NULL, FALSE);
+    g_return_val_if_fail (enabled != NULL, FALSE);
+
+    p = strchr (reply, ':');
+    if (p)
+        p++;
+
+    r = g_regex_new ("\\s*([01])\\s*", 0, 0, NULL);
+    if (!r)
+        return FALSE;
+
+    if (g_regex_match (r, p, 0, &match_info)) {
+        success = TRUE;
+        str = g_match_info_fetch (match_info, 1);
+        if (str) {
+            if (*str == '0')
+                *enabled = FALSE;
+            else if (*str == '1')
+                *enabled = TRUE;
+            else
+                success = FALSE;
+        }
+    }
+    g_match_info_free (match_info);
+    g_regex_unref (r);
+    return success;
+}
+
+/*************************************************************************/
+
 MMModemGsmAccessTech
 mm_gsm_string_to_access_tech (const char *string)
 {
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index a47f469..8a98672 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -58,6 +58,13 @@ gboolean mm_cdma_parse_eri (const char *reply,
 gboolean mm_gsm_parse_cscs_support_response (const char *reply,
                                              MMModemCharset *out_charsets);
 
+gboolean mm_gsm_parse_clck_test_response (const char *reply,
+                                          MMModemGsmFacility *out_facilities);
+gboolean mm_gsm_parse_clck_response (const char *reply,
+                                     gboolean *enabled);
+
+char *mm_gsm_get_facility_name(MMModemGsmFacility facility);
+
 MMModemGsmAccessTech mm_gsm_string_to_access_tech (const char *string);
 
 char *mm_create_device_identifier (guint vid,
-- 
1.7.3.1



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]