aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml6
-rw-r--r--introspection/org.freedesktop.ModemManager.Modem.Gsm.xml37
-rw-r--r--src/mm-generic-gsm.c214
-rw-r--r--src/mm-generic-gsm.h3
-rw-r--r--src/mm-modem-gsm-card.c10
-rw-r--r--src/mm-modem-gsm-card.h3
-rw-r--r--src/mm-modem-helpers.c145
-rw-r--r--src/mm-modem-helpers.h7
8 files changed, 357 insertions, 68 deletions
diff --git a/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml b/introspection/org.freedesktop.ModemManager.Modem.Gsm.Card.xml
index 03c8a9fb..9159052b 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 1abf9155..354ce4a3 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 da0bf5cb..1a0a7fa9 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);
@@ -809,6 +812,30 @@ 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)
{
@@ -882,6 +909,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)) {
@@ -1699,6 +1729,73 @@ cusd_enable_cb (MMAtSerialPort *port,
MM_GENERIC_GSM_GET_PRIVATE (user_data)->ussd_enabled = TRUE;
}
+typedef struct {
+ MMGenericGsmPrivate *priv;
+ MMModemGsmFacility facility;
+} 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 && mm_gsm_parse_clck_response (response->str, &enabled)) {
+ if (enabled)
+ finfo->priv->enabled_facilities |= finfo->facility;
+ else
+ finfo->priv->enabled_facilities &= ~finfo->facility;
+ }
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+ g_free (finfo);
+}
+
+static void
+get_facility_lock_states (MMGenericGsm *self,
+ MMModemGsmFacility facilities,
+ MMAtSerialPort *port,
+ GError *error)
+{
+ gchar *cmd;
+ MMGenericGsmPrivate *priv;
+ gchar *facility_name;
+ FacilityLockInfo *finfo;
+ int i;
+
+ priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+ 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 && mm_serial_port_open (MM_SERIAL_PORT (port), &error)) {
+ cmd = g_strdup_printf ("+CLCK=\"%s\",2", facility_name);
+ finfo = g_malloc0 (sizeof (FacilityLockInfo));
+ finfo->facility = facility;
+ finfo->priv = priv;
+ 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, error);
+ mm_serial_port_close (MM_SERIAL_PORT (port));
+}
+
void
mm_generic_gsm_enable_complete (MMGenericGsm *self,
GError *error,
@@ -2517,10 +2614,10 @@ update_pin_puk_status (MMModem *modem, GError *error)
}
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;
@@ -2581,45 +2678,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,
@@ -2649,24 +2712,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->modem, 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);
@@ -2685,30 +2771,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->modem, 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,
@@ -2721,7 +2790,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);
}
@@ -6043,6 +6112,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);
@@ -6096,6 +6170,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:
@@ -6186,6 +6261,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;
@@ -6306,6 +6384,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 7fba1f31..bbf7988c 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 35360db5..abf642af 100644
--- a/src/mm-modem-gsm-card.c
+++ b/src/mm-modem-gsm-card.c
@@ -659,6 +659,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 34a5d5b7..e6e39dd1 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 0bf62378..25e0561d 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 a47f4695..0827abf2 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,