diff options
-rw-r--r-- | plugins/mm-modem-hso.c | 200 | ||||
-rw-r--r-- | plugins/mm-modem-option.c | 23 | ||||
-rw-r--r-- | src/mm-generic-gsm.c | 43 | ||||
-rw-r--r-- | src/mm-generic-gsm.h | 4 |
4 files changed, 220 insertions, 50 deletions
diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c index fa51bd30..28108ffd 100644 --- a/plugins/mm-modem-hso.c +++ b/plugins/mm-modem-hso.c @@ -9,7 +9,9 @@ #include <dbus/dbus-glib.h> #include "mm-modem-hso.h" #include "mm-serial.h" +#include "mm-serial-parsers.h" #include "mm-errors.h" +#include "mm-util.h" #include "mm-callback-info.h" static void impl_hso_authenticate (MMModemHso *self, @@ -28,7 +30,12 @@ static gpointer mm_modem_hso_parent_class = NULL; typedef struct { char *network_device; - gboolean authenticated; + GRegex *connection_enabled_regex; + gpointer std_parser; + + /* Pending connection attempt */ + MMCallbackInfo *connect_pending_data; + guint connect_pending_id; } MMModemHsoPrivate; enum { @@ -51,6 +58,7 @@ mm_modem_hso_new (const char *serial_device, return MM_MODEM (g_object_new (MM_TYPE_MODEM_HSO, MM_SERIAL_DEVICE, serial_device, + MM_SERIAL_SEND_DELAY, (guint64) 10000, MM_MODEM_DRIVER, driver, MM_MODEM_HSO_NETWORK_DEVICE, network_device, NULL)); @@ -70,6 +78,18 @@ hso_enable_done (MMSerial *serial, mm_callback_info_schedule (info); } +static guint32 +hso_get_cid (MMModemHso *self) +{ + guint32 cid; + + cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); + if (cid == 0) + cid = 1; + + return cid; +} + static void hso_enable (MMModemHso *self, gboolean enabled, @@ -81,25 +101,61 @@ hso_enable (MMModemHso *self, info = mm_callback_info_new (MM_MODEM (self), callback, user_data); - command = g_strdup_printf ("AT_OWANCALL=%d,%d,1", - mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)), - enabled ? 1 : 0); - + command = g_strdup_printf ("AT_OWANCALL=%d,%d,1", hso_get_cid (self), enabled ? 1 : 0); mm_serial_queue_command (MM_SERIAL (self), command, 3, hso_enable_done, info); g_free (command); } static void +connect_pending_done (MMModemHso *self) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + + if (priv->connect_pending_data) { + mm_callback_info_schedule (priv->connect_pending_data); + priv->connect_pending_data = NULL; + } + + if (priv->connect_pending_id) { + g_source_remove (priv->connect_pending_id); + priv->connect_pending_id = 0; + } +} + +static gboolean +hso_connect_timed_out (gpointer data) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (data); + + priv->connect_pending_data->error = g_error_new_literal (MM_SERIAL_ERROR, + MM_SERIAL_RESPONSE_TIMEOUT, + "Connection timed out"); + connect_pending_done (MM_MODEM_HSO (data)); + + return FALSE; +} + +static void hso_enabled (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) + if (error) { info->error = g_error_copy (error); - - mm_callback_info_schedule (info); + mm_callback_info_schedule (info); + } else { + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (modem); + GSource *source; + + source = g_timeout_source_new_seconds (30); + g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (hso_connect_timed_out), G_OBJECT (modem))); + g_source_attach (source, NULL); + priv->connect_pending_data = info; + priv->connect_pending_id = g_source_get_id (source); + g_source_unref (source); + } } static void @@ -140,19 +196,24 @@ mm_hso_modem_authenticate (MMModemHso *self, gpointer user_data) { MMCallbackInfo *info; - char *command; g_return_if_fail (MM_IS_MODEM_HSO (self)); g_return_if_fail (callback != NULL); info = mm_callback_info_new (MM_MODEM (self), callback, user_data); - command = g_strdup_printf ("AT$QCPDPP=%d,1,\"%s\",\"%s\"", - mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)), - password ? password : "", - username ? username : ""); - mm_serial_queue_command (MM_SERIAL (self), command, 3, auth_done, info); - g_free (command); + if (username || password) { + char *command; + + command = g_strdup_printf ("AT$QCPDPP=%d,1,\"%s\",\"%s\"", + hso_get_cid (self), + password ? password : "", + username ? username : ""); + + mm_serial_queue_command (MM_SERIAL (self), command, 3, auth_done, info); + g_free (command); + } else + auth_done (MM_SERIAL (self), NULL, NULL, info); } static void @@ -193,13 +254,13 @@ get_ip4_config_done (MMSerial *serial, if (error) { info->error = g_error_copy (error); goto out; - } else if (g_str_has_prefix (response->str, OWANDATA_TAG)) { + } else if (!g_str_has_prefix (response->str, OWANDATA_TAG)) { info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Retrieving failed: invalid response."); goto out; } - cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (serial)); + cid = hso_get_cid (MM_MODEM_HSO (serial)); dns_array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 2); items = g_strsplit (response->str + strlen (OWANDATA_TAG), ", ", 0); @@ -249,7 +310,7 @@ mm_hso_modem_get_ip4_config (MMModemHso *self, mm_callback_info_set_data (info, "callback", callback, NULL); mm_callback_info_set_data (info, "user-data", user_data, NULL); - command = g_strdup_printf ("AT_OWANDATA=%d", mm_generic_gsm_get_cid (MM_GENERIC_GSM (self))); + command = g_strdup_printf ("AT_OWANDATA=%d", hso_get_cid (self)); mm_serial_queue_command (MM_SERIAL (self), command, 3, get_ip4_config_done, info); g_free (command); } @@ -257,16 +318,45 @@ mm_hso_modem_get_ip4_config (MMModemHso *self, /*****************************************************************************/ static void -modem_enable_done (MMModem *modem, GError *error, gpointer user_data) +pin_check_done (MMModem *modem, GError *error, gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) + info->error = g_error_copy (error); + mm_callback_info_schedule (info); +} + +static void +parent_enable_done (MMModem *modem, GError *error, gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + + if (error) { + info->error = g_error_copy (error); + mm_callback_info_schedule (info); + } else if (GPOINTER_TO_INT (mm_callback_info_get_data (info, "enable")) == FALSE) { + /* Disable, we're done */ + mm_callback_info_schedule (info); + } else { + /* HSO needs manual PIN checking */ + mm_generic_gsm_check_pin (MM_GENERIC_GSM (modem), pin_check_done, info); + } +} + +static void +modem_enable_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMModem *parent_modem_iface; - parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (modem)); - parent_modem_iface->enable (modem, + parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (serial)); + parent_modem_iface->enable (MM_MODEM (serial), GPOINTER_TO_INT (mm_callback_info_get_data (info, "enable")), - (MMModemFn) mm_callback_info_get_data (info, "callback"), - mm_callback_info_get_data (info, "user-data")); + parent_enable_done, info); } static void @@ -277,16 +367,25 @@ enable (MMModem *modem, { MMCallbackInfo *info; - info = mm_callback_info_new (modem, modem_enable_done, NULL); - info->user_data = info; + info = mm_callback_info_new (modem, callback, user_data); mm_callback_info_set_data (info, "enable", GINT_TO_POINTER (enable), NULL); - mm_callback_info_set_data (info, "callback", callback, NULL); - mm_callback_info_set_data (info, "user-data", user_data, NULL); if (enable) - mm_callback_info_schedule (info); + modem_enable_done (MM_SERIAL (modem), NULL, NULL, info); else - hso_enable (MM_MODEM_HSO (modem), FALSE, modem_enable_done, info); + mm_serial_queue_command (MM_SERIAL (modem), "AT_OWANCALL=1,0,0", 3, modem_enable_done, info); +} + +static void +do_connect (MMModem *modem, + const char *number, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + + info = mm_callback_info_new (modem, callback, user_data); + mm_callback_info_schedule (info); } /*****************************************************************************/ @@ -310,6 +409,12 @@ impl_hso_authenticate (MMModemHso *self, const char *password, DBusGMethodInvocation *context) { + /* DBus doesn't support NULLs */ + if (username && strlen (username) == 0) + username = NULL; + if (password && strlen (password) == 0) + password = NULL; + mm_hso_modem_authenticate (self, username, password, impl_hso_auth_done, context); } @@ -335,17 +440,47 @@ impl_hso_get_ip4_config (MMModemHso *self, mm_hso_modem_get_ip4_config (self, impl_hso_ip4_config_done, context); } +static void +connection_enabled (const char *str, gpointer data) +{ + if (str && strlen (str) == 4) { + if (str[3] == '1') + connect_pending_done (MM_MODEM_HSO (data)); + if (str[3] == '0') + /* FIXME: disconnected. do something when we have modem status signals */ + ; + } +} + +static gboolean +hso_parse_response (gpointer data, GString *response, GError **error) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (data); + + mm_util_strip_string (response, priv->connection_enabled_regex, connection_enabled, data); + + return mm_serial_parser_v1_parse (priv->std_parser, response, error); +} + /*****************************************************************************/ static void mm_modem_hso_init (MMModemHso *self) { + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + + priv->connection_enabled_regex = g_regex_new ("_OWANCALL: (\\d, \\d)\\r\\n", + G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + + priv->std_parser = (gpointer) mm_serial_parser_v1_new (); + mm_serial_set_response_parser (MM_SERIAL (self), hso_parse_response, self, NULL); } static void modem_init (MMModem *modem_class) { modem_class->enable = enable; + modem_class->connect = do_connect; } static GObject* @@ -410,7 +545,12 @@ finalize (GObject *object) { MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (object); + /* Clear the pending connection if necessary */ + connect_pending_done (MM_MODEM_HSO (object)); + g_free (priv->network_device); + g_regex_unref (priv->connection_enabled_regex); + mm_serial_parser_v1_destroy (priv->std_parser); G_OBJECT_CLASS (mm_modem_hso_parent_class)->finalize (object); } @@ -462,6 +602,8 @@ mm_modem_hso_get_type (void) modem_hso_type = g_type_register_static (MM_TYPE_GENERIC_GSM, "MMModemHso", &modem_hso_type_info, 0); g_type_add_interface_static (modem_hso_type, MM_TYPE_MODEM, &modem_iface_info); + + dbus_g_object_type_install_info (modem_hso_type, &dbus_glib_mm_modem_gsm_hso_object_info); } return modem_hso_type; diff --git a/plugins/mm-modem-option.c b/plugins/mm-modem-option.c index c5800d8f..a45bc36e 100644 --- a/plugins/mm-modem-option.c +++ b/plugins/mm-modem-option.c @@ -24,31 +24,12 @@ mm_modem_option_new (const char *data_device, } static void -check_pin_done (MMSerial *serial, - GString *response, - GError *error, - gpointer user_data) +pin_check_done (MMModem *modem, GError *error, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - gboolean parsed = FALSE; if (error) info->error = g_error_copy (error); - else if (g_str_has_prefix (response->str, "+CPIN: ")) { - const char *str = response->str + 7; - - if (g_str_has_prefix (str, "READY")) - parsed = TRUE; - else if (g_str_has_prefix (str, "SIM PIN")) - info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PIN); - else if (g_str_has_prefix (str, "SIM PUK")) - info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PUK); - } - - if (!info->error && !parsed) - info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "%s", "Could not parse PIN request results"); - mm_callback_info_schedule (info); } @@ -66,7 +47,7 @@ parent_enable_done (MMModem *modem, GError *error, gpointer user_data) /* Now check the PIN explicitly, option doesn't seem to report that it needs it otherwise */ - mm_serial_queue_command (MM_SERIAL (modem), "+CPIN?", 3, check_pin_done, info); + mm_generic_gsm_check_pin (MM_GENERIC_GSM (modem), pin_check_done, info); return; } diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 2f0be962..e1769c8d 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -85,6 +85,49 @@ mm_generic_gsm_set_operator (MMGenericGsm *modem, priv->oper_name = g_strdup (name); } +static void +pin_check_done (MMSerial *serial, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + gboolean parsed = FALSE; + + if (error) + info->error = g_error_copy (error); + else if (g_str_has_prefix (response->str, "+CPIN: ")) { + const char *str = response->str + 7; + + if (g_str_has_prefix (str, "READY")) + parsed = TRUE; + else if (g_str_has_prefix (str, "SIM PIN")) + info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PIN); + else if (g_str_has_prefix (str, "SIM PUK")) + info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_SIM_PUK); + /* FIXME: There's more exotic ones that are not handled right now */ + } + + if (!info->error && !parsed) + info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "%s", "Could not parse PIN request results"); + + mm_callback_info_schedule (info); +} + +void +mm_generic_gsm_check_pin (MMGenericGsm *modem, + MMModemFn callback, + gpointer user_data) +{ + MMCallbackInfo *info; + + g_return_if_fail (MM_IS_GENERIC_GSM (modem)); + + info = mm_callback_info_new (MM_MODEM (modem), callback, user_data); + mm_serial_queue_command (MM_SERIAL (modem), "+CPIN?", 3, pin_check_done, info); +} + /*****************************************************************************/ static void diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index 621bad7f..ec8428f5 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -37,4 +37,8 @@ void mm_generic_gsm_set_operator (MMGenericGsm *modem, const char *code, const char *name); +void mm_generic_gsm_check_pin (MMGenericGsm *modem, + MMModemFn callback, + gpointer user_data); + #endif /* MM_GENERIC_GSM_H */ |