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




From e9ed4df79c1159a51b919f9bf7745370f015dd76 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                               |  235 ++++++++++++++------
 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, 375 insertions(+), 71 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 e00e3c8..e2e0eac 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -138,6 +138,9 @@ typedef struct {
     GHashTable *sms_parts;
 
     guint sms_fetch_pending;
+
+    /* Facility locks */
+    MMModemGsmFacility enabled_facilities;
 } MMGenericGsmPrivate;
 
 static void get_registration_status (MMAtSerialPort *port, MMCallbackInfo *info);
@@ -808,6 +811,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)
 {
@@ -881,6 +907,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)) {
@@ -1698,6 +1727,86 @@ cusd_enable_cb (MMAtSerialPort *port,
     MM_GENERIC_GSM_GET_PRIVATE (user_data)->ussd_enabled = TRUE;
 }
 
+typedef struct {
+    MMGenericGsmPrivate *priv;
+    MMModemGsmFacility facility;
+    gboolean last;
+} FacilityLockInfo;
+
+static void
+get_facility_lock_state_done (MMAtSerialPort *port,
+                              GString *response,
+                              GError *error,
+                              gpointer user_data)
+{
+    gboolean enabled = FALSE;
+    FacilityLockInfo *finfo = (FacilityLockInfo *)user_data;
+
+    if (error) {
+        g_free (finfo);
+        return;
+    }
+
+    if (mm_gsm_parse_clck_response (response->str, &enabled)) {
+        if (enabled)
+            finfo->priv->enabled_facilities |= finfo->facility;
+        else
+            finfo->priv->enabled_facilities &= ~finfo->facility;
+    }
+    if (finfo->last)
+        mm_serial_port_close (MM_SERIAL_PORT (port));
+    g_free (finfo);
+}
+
+static void
+get_facility_lock_states (MMGenericGsm *self, MMModemGsmFacility facilities, MMAtSerialPort *port)
+{
+    gchar *cmd;
+    MMGenericGsmPrivate *priv;
+    gchar *facility_name;
+    FacilityLockInfo *finfo;
+    int i, last_index;
+    guint32 mask;
+
+    priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+    mask = facilities;
+    for (i = 0; mask && i < sizeof (MMModemGsmFacility)*8; i++) {
+        mask >>= 1;
+    }
+    last_index = i - 1;
+
+    for (i = 0; i < sizeof (MMModemGsmFacility)*8; i++) {
+        guint32 facility = 1 << i;
+        if (facilities & facility) {
+            facility_name = mm_gsm_get_facility_name (facility);
+            if (facility_name != NULL) {
+                cmd = g_strdup_printf ("+CLCK=\"%s\",2", facility_name);
+                finfo = g_malloc0 (sizeof (FacilityLockInfo));
+                finfo->facility = facility;
+                finfo->priv = priv;
+                if (i == last_index)
+                    finfo->last = TRUE;
+                mm_at_serial_port_queue_command (port, cmd, 3, get_facility_lock_state_done, finfo);
+                g_free (cmd);
+            }
+        }
+    }
+}
+
+static void
+clck_cb (MMAtSerialPort *port,
+         GString *response,
+         GError *error,
+         gpointer user_data)
+{
+    MMModemGsmFacility facilities;
+
+    if (!error && mm_gsm_parse_clck_test_response (response->str, &facilities))
+        get_facility_lock_states (MM_GENERIC_GSM (user_data), facilities, port);
+    else
+        mm_serial_port_close (MM_SERIAL_PORT (port));
+}
+
 void
 mm_generic_gsm_enable_complete (MMGenericGsm *self,
                                 GError *error,
@@ -2488,32 +2597,35 @@ 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);
 }
 
 static void
-send_puk_done (MMAtSerialPort *port,
-               GString *response,
-               GError *error,
-               gpointer user_data)
+send_pin_puk_done (MMAtSerialPort *port,
+                   GString *response,
+                   GError *error,
+                   gpointer user_data)
 {
     MMCallbackInfo *info = (MMCallbackInfo *) user_data;
 
@@ -2574,45 +2686,11 @@ send_puk (MMModemGsmCard *modem,
     mm_callback_info_set_data (info, PIN_PORT_TAG, port, NULL);
 
     command = g_strdup_printf ("+CPIN=\"%s\",\"%s\"", puk, pin);
-    mm_at_serial_port_queue_command (port, command, 3, send_puk_done, info);
+    mm_at_serial_port_queue_command (port, command, 3, send_pin_puk_done, info);
     g_free (command);
 }
 
 static void
-send_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;
-
-    if (error) {
-        if (error->domain != MM_MOBILE_ERROR) {
-            info->error = g_error_copy (error);
-            mm_callback_info_schedule (info);
-            mm_serial_port_close (MM_SERIAL_PORT (port));
-            return;
-        } else {
-            /* Keep the real error around so we can send it back
-             * when we're done rechecking CPIN status.
-             */
-            mm_callback_info_set_data (info, SAVED_ERROR_TAG,
-                                       g_error_copy (error),
-                                       (GDestroyNotify) g_error_free);
-        }
-    }
-
-    /* Get latest PIN status */
-    MM_GENERIC_GSM_GET_PRIVATE (info->modem)->pin_check_tries = 0;
-    check_pin (MM_GENERIC_GSM (info->modem), pin_puk_recheck_done, info);
-}
-
-static void
 send_pin (MMModemGsmCard *modem,
           const char *pin,
           MMModemFn callback,
@@ -2642,24 +2720,47 @@ send_pin (MMModemGsmCard *modem,
     mm_callback_info_set_data (info, PIN_PORT_TAG, port, NULL);
 
     command = g_strdup_printf ("+CPIN=\"%s\"", pin);
-    mm_at_serial_port_queue_command (port, command, 3, send_pin_done, info);
+    mm_at_serial_port_queue_command (port, command, 3, send_pin_puk_done, info);
     g_free (command);
 }
 
+#define ENABLED_FACILITY_TAG "enabled-facility"
+#define ENABLED_TAG "enabled"
+
 static void
-enable_pin_done (MMAtSerialPort *port,
-                 GString *response,
-                 GError *error,
-                 gpointer user_data)
+pin_operation_done (MMAtSerialPort *port,
+                    GString *response,
+                    GError *error,
+                    gpointer user_data)
 {
     MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+    MMGenericGsmPrivate *priv;
+    MMModem *modem;
+    MMModemGsmFacility facility;
+    gboolean enabled;
 
     /* 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) {
+        facility = GPOINTER_TO_UINT (mm_callback_info_get_data (info, ENABLED_FACILITY_TAG));
+        enabled = GPOINTER_TO_UINT (mm_callback_info_get_data (info, ENABLED_TAG));
+        if (facility != MM_MODEM_GSM_FACILITY_NONE) {
+            MMModemGsmFacility old = priv->enabled_facilities;
+            if (enabled)
+                priv->enabled_facilities |= facility;
+            else
+                priv->enabled_facilities &= ~facility;
+            if (priv->enabled_facilities != old)
+                g_object_notify (G_OBJECT (modem),
+                                 MM_MODEM_GSM_CARD_ENABLED_FACILITY_LOCKS);
+        }
+    }
+    update_pin_puk_status (modem, error);
     if (error)
         info->error = g_error_copy (error);
     mm_callback_info_schedule (info);
@@ -2678,30 +2779,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);
+    mm_callback_info_set_data (info, ENABLED_FACILITY_TAG, GUINT_TO_POINTER(MM_MODEM_GSM_FACILITY_SIM), NULL);
+    mm_callback_info_set_data (info, ENABLED_TAG, GUINT_TO_POINTER(enabled), NULL);
+    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,
@@ -2714,7 +2798,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);
 }
 
@@ -6040,6 +6124,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);
@@ -6093,6 +6182,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:
@@ -6183,6 +6273,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;
@@ -6303,6 +6396,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 0bf6237..fe0ba7a 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -819,6 +819,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]