[network-manager-netbook] Update the mobile providers parser to parse the format "2.0".



commit 15e821630a7cd6f7a2d3ee5f8daffb72b6a06a9c
Author: Tambet Ingo <tambet gmail com>
Date:   Thu Jun 4 13:32:39 2009 +0300

    Update the mobile providers parser to parse the format "2.0".
    Use the new MCC and MNC in created mobile connections.
---
 src/nmn-mobile-providers.c |  409 +++++++++++++++++++++++++++++++++++++++++---
 src/nmn-mobile-providers.h |   45 +++++-
 src/nmn-new-connection.c   |  168 +++++++++++++-----
 3 files changed, 548 insertions(+), 74 deletions(-)

diff --git a/src/nmn-mobile-providers.c b/src/nmn-mobile-providers.c
index bd582a0..d8d4ecf 100644
--- a/src/nmn-mobile-providers.c
+++ b/src/nmn-mobile-providers.c
@@ -20,6 +20,11 @@
  */
 
 #include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
 #include "nmn-mobile-providers.h"
 
 #define ISO_3166_COUNTRY_CODES "/usr/share/zoneinfo/iso3166.tab"
@@ -86,7 +91,11 @@ read_country_codes (void)
 typedef enum {
     PARSER_TOPLEVEL = 0,
     PARSER_COUNTRY,
-    PARSER_PROVIDER
+    PARSER_PROVIDER,
+    PARSER_METHOD_GSM,
+    PARSER_METHOD_GSM_APN,
+    PARSER_METHOD_CDMA,
+    PARSER_ERROR
 } MobileContextState;
 
 typedef struct {
@@ -96,11 +105,111 @@ typedef struct {
     char *current_country;
     GSList *current_providers;
     NmnMobileProvider *current_provider;
+    NmnMobileAccessMethod *current_method;
+    GSList *mcc_mncs;
 
     char *text_buffer;
     MobileContextState state;
 } MobileParser;
 
+static NmnGsmMccMnc *
+mcc_mnc_new (const char *mcc, const char *mnc)
+{
+    NmnGsmMccMnc *m;
+
+    m = g_slice_new0 (NmnGsmMccMnc);
+    m->mcc = g_strdup (mcc);
+    m->mnc = g_strdup (mnc);
+    return m;
+}
+
+static void
+mcc_mnc_free (NmnGsmMccMnc *m)
+{
+    g_return_if_fail (m != NULL);
+    g_free (m->mcc);
+    g_free (m->mnc);
+    g_slice_free (NmnGsmMccMnc, m);
+}
+
+static GSList *
+mcc_mnc_list_copy (GSList *list)
+{
+    GSList *iter, *ret = NULL;
+
+    for (iter = list; iter; iter = g_slist_next (iter)) {
+        NmnGsmMccMnc *m = iter->data;
+
+        ret = g_slist_prepend (ret, mcc_mnc_new (m->mcc, m->mnc));
+    }
+
+    return g_slist_reverse (ret);
+}
+
+static NmnMobileAccessMethod *
+access_method_new (void)
+{
+    NmnMobileAccessMethod *method;
+
+    method = g_slice_new0 (NmnMobileAccessMethod);
+    method->refs = 1;
+    method->lcl_names = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                               (GDestroyNotify) g_free,
+                                               (GDestroyNotify) g_free);
+
+    return method;
+}
+
+NmnMobileAccessMethod *
+nmn_mobile_access_method_ref (NmnMobileAccessMethod *method)
+{
+    g_return_val_if_fail (method != NULL, NULL);
+    g_return_val_if_fail (method->refs > 0, NULL);
+ 
+    method->refs++;
+
+    return method;
+}
+
+void
+nmn_mobile_access_method_unref (NmnMobileAccessMethod *method)
+{
+    g_return_if_fail (method != NULL);
+    g_return_if_fail (method->refs > 0);
+
+    if (--method->refs == 0) {
+        g_free (method->name);
+        g_hash_table_destroy (method->lcl_names);
+        g_free (method->username);
+        g_free (method->password);
+        g_free (method->gateway);
+        g_free (method->gsm_apn);
+        g_slist_foreach (method->dns, (GFunc) g_free, NULL);
+        g_slist_free (method->dns);
+
+        g_slist_foreach (method->gsm_mcc_mnc, (GFunc) mcc_mnc_free, NULL);
+        g_slist_free (method->gsm_mcc_mnc);
+
+        g_slist_free (method->cdma_sid);
+
+        g_slice_free (NmnMobileAccessMethod, method);
+    }
+}
+
+GType
+nmn_mobile_access_method_get_type (void)
+{
+    static GType type = 0;
+
+    if (G_UNLIKELY (type == 0)) {
+        type = g_boxed_type_register_static ("NmnMobileAccessMethod",
+                                             (GBoxedCopyFunc) nmn_mobile_access_method_ref,
+                                             (GBoxedFreeFunc) nmn_mobile_access_method_unref);
+    }
+    return type;
+}
+
+
 static NmnMobileProvider *
 provider_new (void)
 {
@@ -108,6 +217,9 @@ provider_new (void)
 
     provider = g_slice_new0 (NmnMobileProvider);
     provider->refs = 1;
+    provider->lcl_names = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                                 (GDestroyNotify) g_free,
+                                                 (GDestroyNotify) g_free);
 
     return provider;
 }
@@ -125,12 +237,10 @@ nmn_mobile_provider_unref (NmnMobileProvider *provider)
 {
     if (--provider->refs == 0) {
         g_free (provider->name);
-        g_free (provider->username);
-        g_free (provider->password);
-        g_free (provider->gateway);
-        g_free (provider->apn);
-        g_slist_foreach (provider->dns, (GFunc) g_free, NULL);
-        g_slist_free (provider->dns);
+        g_hash_table_destroy (provider->lcl_names);
+
+        g_slist_foreach (provider->methods, (GFunc) nmn_mobile_access_method_unref, NULL);
+        g_slist_free (provider->methods);
 
         g_slice_free (NmnMobileProvider, provider);
     }
@@ -141,11 +251,11 @@ nmn_mobile_provider_get_type (void)
 {
     static GType type = 0;
 
-    if (G_UNLIKELY (type == 0))
+    if (G_UNLIKELY (type == 0)) {
         type = g_boxed_type_register_static ("NmnMobileProvider",
                                              (GBoxedCopyFunc) nmn_mobile_provider_ref,
                                              (GBoxedFreeFunc) nmn_mobile_provider_unref);
-
+    }
     return type;
 }
 
@@ -168,7 +278,18 @@ parser_toplevel_start (MobileParser *parser,
 {
     int i;
 
-    if (!strcmp (name, "country")) {
+    if (!strcmp (name, "serviceproviders")) {
+        for (i = 0; attribute_names && attribute_names[i]; i++) {
+            if (!strcmp (attribute_names[i], "format")) {
+                if (strcmp (attribute_values[i], "2.0")) {
+                    g_warning ("%s: mobile broadband provider database format '%s'"
+                               " not supported.", __func__, attribute_values[i]);
+                    parser->state = PARSER_ERROR;
+                    break;
+                }
+            }
+        }
+    } else if (!strcmp (name, "country")) {
         for (i = 0; attribute_names && attribute_names[i]; i++) {
             if (!strcmp (attribute_names[i], "code")) {
                 char *country_code;
@@ -202,6 +323,80 @@ parser_country_start (MobileParser *parser,
 }
 
 static void
+parser_provider_start (MobileParser *parser,
+                       const char *name,
+                       const char **attribute_names,
+                       const char **attribute_values)
+{
+    if (!strcmp (name, "gsm"))
+        parser->state = PARSER_METHOD_GSM;
+    else if (!strcmp (name, "cdma")) {
+        parser->state = PARSER_METHOD_CDMA;
+        parser->current_method = access_method_new ();
+    }
+}
+
+static void
+parser_gsm_start (MobileParser *parser,
+                       const char *name,
+                       const char **attribute_names,
+                       const char **attribute_values)
+{
+    if (!strcmp (name, "network-id")) {
+        const char *mcc = NULL, *mnc = NULL;
+        int i;
+
+        for (i = 0; attribute_names && attribute_names[i]; i++) {
+            if (!strcmp (attribute_names[i], "mcc"))
+                mcc = attribute_values[i];
+            else if (!strcmp (attribute_names[i], "mnc"))
+                mnc = attribute_values[i];
+
+            if (mcc && strlen (mcc) && mnc && strlen (mnc)) {
+                parser->mcc_mncs = g_slist_append (parser->mcc_mncs, mcc_mnc_new (mcc, mnc));
+                break;
+            }
+        }
+    } else if (!strcmp (name, "apn")) {
+        int i;
+
+        for (i = 0; attribute_names && attribute_names[i]; i++) {
+            if (!strcmp (attribute_names[i], "value")) {
+
+                parser->state = PARSER_METHOD_GSM_APN;
+                parser->current_method = access_method_new ();
+                parser->current_method->gsm_apn = g_strdup (attribute_values[i]);
+                break;
+            }
+        }
+    }
+}
+
+static void
+parser_cdma_start (MobileParser *parser,
+                   const char *name,
+                   const char **attribute_names,
+                   const char **attribute_values)
+{
+    if (!strcmp (name, "sid")) {
+        int i;
+
+        for (i = 0; attribute_names && attribute_names[i]; i++) {
+            if (!strcmp (attribute_names[i], "value")) {
+                unsigned long tmp;
+
+                errno = 0;
+                tmp = strtoul (attribute_values[i], NULL, 10);
+                if (errno == 0 && tmp > 0)
+                    parser->current_method->cdma_sid = g_slist_prepend (parser->current_method->cdma_sid,
+                                                                        GUINT_TO_POINTER ((guint32) tmp));
+                break;
+            }
+        }
+    }
+}
+
+static void
 mobile_parser_start_element (GMarkupParseContext *context,
                              const gchar *element_name,
                              const gchar **attribute_names,
@@ -223,6 +418,15 @@ mobile_parser_start_element (GMarkupParseContext *context,
     case PARSER_COUNTRY:
         parser_country_start (parser, element_name, attribute_names, attribute_values);
         break;
+    case PARSER_PROVIDER:
+        parser_provider_start (parser, element_name, attribute_names, attribute_values);
+        break;
+    case PARSER_METHOD_GSM:
+        parser_gsm_start (parser, element_name, attribute_names, attribute_values);
+        break;
+    case PARSER_METHOD_CDMA:
+        parser_cdma_start (parser, element_name, attribute_names, attribute_values);
+        break;
     default:
         break;
     }
@@ -250,28 +454,92 @@ parser_provider_end (MobileParser *parser,
             parser->current_provider->name = parser->text_buffer;
             parser->text_buffer = NULL;
         }
+    } else if (!strcmp (name, "provider")) {
+        parser->current_provider->methods = g_slist_reverse (parser->current_provider->methods);
+
+        parser->current_providers = g_slist_prepend (parser->current_providers, parser->current_provider);
+        parser->current_provider = NULL;
+        parser->state = PARSER_COUNTRY;
+    }
+}
+
+static void
+parser_gsm_end (MobileParser *parser,
+                 const char *name)
+{
+    if (!strcmp (name, "gsm")) {
+        g_slist_foreach (parser->mcc_mncs, (GFunc) mcc_mnc_free, NULL);
+        g_slist_free (parser->mcc_mncs);
+        parser->mcc_mncs = NULL;
+        parser->state = PARSER_PROVIDER;
+    }
+}
+
+static void
+parser_gsm_apn_end (MobileParser *parser,
+                    const char *name)
+{
+    if (!strcmp (name, "name")) {
+        if (!parser->current_method->name) {
+            /* Use the first one. */
+            parser->current_method->name = parser->text_buffer;
+            parser->text_buffer = NULL;
+        }
     } else if (!strcmp (name, "username")) {
-        parser->current_provider->username = parser->text_buffer;
+        parser->current_method->username = parser->text_buffer;
         parser->text_buffer = NULL;
     } else if (!strcmp (name, "password")) {
-        parser->current_provider->password = parser->text_buffer;
+        parser->current_method->password = parser->text_buffer;
         parser->text_buffer = NULL;
     } else if (!strcmp (name, "dns")) {
-        parser->current_provider->dns = g_slist_prepend (parser->current_provider->dns, parser->text_buffer);
+        parser->current_method->dns = g_slist_prepend (parser->current_method->dns, parser->text_buffer);
         parser->text_buffer = NULL;
     } else if (!strcmp (name, "gateway")) {
-        parser->current_provider->gateway = parser->text_buffer;
+        parser->current_method->gateway = parser->text_buffer;
         parser->text_buffer = NULL;
     } else if (!strcmp (name, "apn")) {
-        parser->current_provider->apn = parser->text_buffer;
+        parser->current_method->type = NMN_MOBILE_ACCESS_METHOD_TYPE_GSM;
+        parser->current_method->dns = g_slist_reverse (parser->current_method->dns);
+        parser->current_method->gsm_mcc_mnc = mcc_mnc_list_copy (parser->mcc_mncs);
+
+        if (!parser->current_method->name)
+            parser->current_method->name = g_strdup (_("Default"));
+
+        parser->current_provider->methods = g_slist_prepend (parser->current_provider->methods,
+                                                             parser->current_method);
+        parser->current_method = NULL;
+        parser->state = PARSER_METHOD_GSM;
+    }
+}
+
+static void
+parser_cdma_end (MobileParser *parser,
+                 const char *name)
+{
+    if (!strcmp (name, "username")) {
+        parser->current_method->username = parser->text_buffer;
+        parser->text_buffer = NULL;
+    } else if (!strcmp (name, "password")) {
+        parser->current_method->password = parser->text_buffer;
+        parser->text_buffer = NULL;
+    } else if (!strcmp (name, "dns")) {
+        parser->current_method->dns = g_slist_prepend (parser->current_method->dns, parser->text_buffer);
+        parser->text_buffer = NULL;
+    } else if (!strcmp (name, "gateway")) {
+        parser->current_method->gateway = parser->text_buffer;
         parser->text_buffer = NULL;
     } else if (!strcmp (name, "cdma")) {
-        parser->current_provider->type = NMN_PROVIDER_TYPE_CDMA;
-    } else if (!strcmp (name, "provider")) {
-        parser->current_provider->dns = g_slist_reverse (parser->current_provider->dns);
-        parser->current_providers = g_slist_prepend (parser->current_providers, parser->current_provider);
-        parser->current_provider = NULL;
-        parser->state = PARSER_COUNTRY;
+        parser->current_method->type = NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA;
+        parser->current_method->dns = g_slist_reverse (parser->current_method->dns);
+        parser->current_method->cdma_sid = g_slist_reverse (parser->current_method->cdma_sid);
+
+        if (!parser->current_method->name)
+            parser->current_method->name = g_strdup (parser->current_provider->name);
+
+        parser->current_provider->methods = g_slist_prepend (parser->current_provider->methods,
+                                                             parser->current_method);
+        parser->current_method = NULL;
+        parser->state = PARSER_PROVIDER;
     }
 }
 
@@ -290,6 +558,15 @@ mobile_parser_end_element (GMarkupParseContext *context,
     case PARSER_PROVIDER:
         parser_provider_end (parser, element_name);
         break;
+    case PARSER_METHOD_GSM:
+        parser_gsm_end (parser, element_name);
+        break;
+    case PARSER_METHOD_GSM_APN:
+        parser_gsm_apn_end (parser, element_name);
+        break;
+    case PARSER_METHOD_CDMA:
+        parser_cdma_end (parser, element_name);
+        break;
     default:
         break;
     }
@@ -317,7 +594,7 @@ static const GMarkupParser mobile_parser = {
 };
 
 GHashTable *
-nmn_mobile_providers_parse (void)
+nmn_mobile_providers_parse (GHashTable **out_ccs)
 {
     GMarkupParseContext *ctx;
     GIOChannel *channel;
@@ -390,8 +667,92 @@ nmn_mobile_providers_parse (void)
     g_free (parser.text_buffer);
 
  out:
-    if (parser.country_codes)
-        g_hash_table_destroy (parser.country_codes);
+    if (parser.country_codes) {
+        if (out_ccs)
+            *out_ccs = parser.country_codes;
+        else
+            g_hash_table_destroy (parser.country_codes);
+    }
 
     return parser.table;
 }
+
+static void
+dump_generic (NmnMobileAccessMethod *method)
+{
+    GSList *iter;
+    GString *dns;
+
+    g_print ("        username: %s\n", method->username ? method->username : "");
+    g_print ("        password: %s\n", method->password ? method->password : "");
+
+    dns = g_string_new (NULL);
+    for (iter = method->dns; iter; iter = g_slist_next (iter))
+        g_string_append_printf (dns, "%s%s", dns->len ? ", " : "", (char *) iter->data);
+    g_print ("        dns     : %s\n", dns->str);
+    g_string_free (dns, TRUE);
+
+    g_print ("        gateway : %s\n", method->gateway ? method->gateway : "");
+}
+
+static void
+dump_cdma (NmnMobileAccessMethod *method)
+{
+    GSList *iter;
+
+    g_print ("     CDMA: %s\n", method->name);
+
+    dump_generic (method);
+
+    for (iter = method->cdma_sid; iter; iter = g_slist_next (iter))
+        g_print ("        SID: %d\n", GPOINTER_TO_UINT (iter->data));
+}
+
+static void
+dump_gsm (NmnMobileAccessMethod *method)
+{
+    GSList *iter;
+
+    g_print ("     APN: %s (%s)\n", method->name, method->gsm_apn);
+
+    dump_generic (method);
+
+    for (iter = method->gsm_mcc_mnc; iter; iter = g_slist_next (iter)) {
+        NmnGsmMccMnc *m = iter->data;
+        g_print ("        MCC/MNC: %s-%s\n", m->mcc, m->mnc);
+    }
+}
+
+static void
+dump_country (gpointer key, gpointer value, gpointer user_data)
+{
+    GSList *citer, *miter;
+
+    for (citer = value; citer; citer = g_slist_next (citer)) {
+        NmnMobileProvider *provider = citer->data;
+
+        g_print ("Provider: %s (%s)\n", provider->name, (const char *) key);
+        for (miter = provider->methods; miter; miter = g_slist_next (miter)) {
+            NmnMobileAccessMethod *method = miter->data;
+
+            switch (method->type) {
+            case NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA:
+                dump_cdma (method);
+                break;
+            case NMN_MOBILE_ACCESS_METHOD_TYPE_GSM:
+                dump_gsm (method);
+                break;
+            default:
+                break;
+            }
+            g_print ("\n");
+        }
+    }
+}
+
+void
+nmn_mobile_providers_dump (GHashTable *providers)
+{
+    g_return_if_fail (providers != NULL);
+    g_hash_table_foreach (providers, dump_country, NULL);
+}
diff --git a/src/nmn-mobile-providers.h b/src/nmn-mobile-providers.h
index 5c0c158..371fdef 100644
--- a/src/nmn-mobile-providers.h
+++ b/src/nmn-mobile-providers.h
@@ -26,34 +26,67 @@
 #include <glib-object.h>
 
 #define NMN_TYPE_MOBILE_PROVIDER (nmn_mobile_provider_get_type ())
+#define NMN_TYPE_MOBILE_ACCESS_METHOD (nmn_mobile_access_method_get_type ())
 
 typedef enum {
-    NMN_PROVIDER_TYPE_GSM = 0,
-    NMN_PROVIDER_TYPE_CDMA
+    NMN_MOBILE_ACCESS_METHOD_TYPE_UNKNOWN = 0,
+    NMN_MOBILE_ACCESS_METHOD_TYPE_GSM,
+    NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA
 } NmnMobileProviderType;
 
 typedef struct {
+    char *mcc;
+    char *mnc;
+} NmnGsmMccMnc;
+
+typedef struct {
     char *name;
+    /* maps lang (char *) -> name (char *) */
+    GHashTable *lcl_names;
+
     char *username;
     char *password;
     char *gateway;
-    char *apn;
     GSList *dns; /* GSList of 'char *' */
+
+    /* Only used with NMN_PROVIDER_TYPE_GSM */
+    char *gsm_apn;
+    GSList *gsm_mcc_mnc; /* GSList of NmnGsmMccMnc */
+
+    /* Only used with NMN_PROVIDER_TYPE_CDMA */
+    GSList *cdma_sid; /* GSList of guint32 */
+
     NmnMobileProviderType type;
 
     gint refs;
+} NmnMobileAccessMethod;
+
+typedef struct {
+    char *name;
+    /* maps lang (char *) -> name (char *) */
+    GHashTable *lcl_names;
+
+    GSList *methods; /* GSList of NmnMobileAccessMethod */
+
+    gint refs;
 } NmnMobileProvider;
 
+
 GType nmn_mobile_provider_get_type (void);
+GType nmn_mobile_access_method_get_type (void);
 
 NmnMobileProvider *nmn_mobile_provider_ref   (NmnMobileProvider *provider);
-void                   nmn_mobile_provider_unref (NmnMobileProvider *provider);
+void               nmn_mobile_provider_unref (NmnMobileProvider *provider);
+
+NmnMobileAccessMethod *nmn_mobile_access_method_ref   (NmnMobileAccessMethod *method);
+void                   nmn_mobile_access_method_unref (NmnMobileAccessMethod *method);
 
 /* Returns a hash table where keys are country names 'char *',
-   values are NmnMobileProvider structures.
+   values are a 'GSList *' of 'NmnMobileProvider *'.
    Everything is destroyed with g_hash_table_destroy (). */
 
-GHashTable *nmn_mobile_providers_parse (void);
+GHashTable *nmn_mobile_providers_parse (GHashTable **out_ccs);
 
+void nmn_mobile_providers_dump (GHashTable *providers);
 
 #endif /* NMN_MOBILE_PROVIDERS_H */
diff --git a/src/nmn-new-connection.c b/src/nmn-new-connection.c
index 907392e..2b9d03f 100644
--- a/src/nmn-new-connection.c
+++ b/src/nmn-new-connection.c
@@ -94,8 +94,9 @@ wifi_page_init (NmnNewConnection *connection)
 
 /* Mobile */
 
-#define MOBILE_COL_NAME 0
-#define MOBILE_COL_DATA 1
+#define MOBILE_COL_NAME     0
+#define MOBILE_COL_PROVIDER 1
+#define MOBILE_COL_METHOD   2
 
 static gboolean
 mobile_have_device (NmnNewConnection *connection, NmnMobileProviderType *type)
@@ -111,12 +112,12 @@ mobile_have_device (NmnNewConnection *connection, NmnMobileProviderType *type)
 
         if (NM_IS_GSM_DEVICE (device)) {
             found = TRUE;
-            *type = NMN_PROVIDER_TYPE_GSM;
+            *type = NMN_MOBILE_ACCESS_METHOD_TYPE_GSM;
         }
 
         if (NM_IS_CDMA_DEVICE (device)) {
             found = TRUE;
-            *type = NMN_PROVIDER_TYPE_CDMA;
+            *type = NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA;
         }
     }
 
@@ -147,6 +148,21 @@ mobile_status_update (NmnNewConnection *connection)
 }
 
 static gboolean
+method_list_has_type (GSList *list, NmnMobileProviderType type)
+{
+    GSList *iter;
+
+    for (iter = list; iter; iter = iter->next) {
+        NmnMobileAccessMethod *method = iter->data;
+
+        if (method->type == type)
+            return TRUE;
+    }
+
+    return FALSE;
+}
+
+static gboolean
 provider_list_has_type (GSList *list, NmnMobileProviderType type)
 {
     GSList *iter;
@@ -154,7 +170,7 @@ provider_list_has_type (GSList *list, NmnMobileProviderType type)
     for (iter = list; iter; iter = iter->next) {
         NmnMobileProvider *provider = (NmnMobileProvider *) iter->data;
 
-        if (provider->type == type)
+        if (method_list_has_type (provider->methods, type))
             return TRUE;
     }
 
@@ -164,37 +180,80 @@ provider_list_has_type (GSList *list, NmnMobileProviderType type)
 typedef struct {
     GtkTreeStore *store;
     NmnMobileProviderType provider_type;
+
+    GtkTreeIter *parent_iter;
 } MobilePopulateInfo;
 
 static void
+add_one_method (gpointer data, gpointer user_data)
+{
+    NmnMobileAccessMethod *method = (NmnMobileAccessMethod *) data;
+    MobilePopulateInfo *info = (MobilePopulateInfo *) user_data;
+    GtkTreeIter iter;
+
+    if (method->type != info->provider_type)
+        return;
+
+    gtk_tree_store_append (info->store, &iter, info->parent_iter);
+
+    if (method->type == NMN_MOBILE_ACCESS_METHOD_TYPE_GSM) {
+        char *txt;
+
+        txt = g_strdup_printf ("%s (APN %s)", method->name, method->gsm_apn);
+        gtk_tree_store_set (info->store, &iter,
+                            MOBILE_COL_NAME, txt,
+                            MOBILE_COL_METHOD, method,
+                            -1);
+
+        g_free (txt);
+    } else {
+        gtk_tree_store_set (info->store, &iter,
+                            MOBILE_COL_NAME, method->name,
+                            MOBILE_COL_METHOD, method,
+                            -1);
+    }
+}
+
+static void
+add_one_provider (gpointer data, gpointer user_data)
+{
+    NmnMobileProvider *provider = (NmnMobileProvider *) data;
+    MobilePopulateInfo *info = (MobilePopulateInfo *) user_data;
+    GtkTreeIter *country_iter;
+    GtkTreeIter iter;
+
+    if (!method_list_has_type (provider->methods, info->provider_type))
+        return;
+
+    gtk_tree_store_append (info->store, &iter, info->parent_iter);
+    gtk_tree_store_set (info->store, &iter,
+                        MOBILE_COL_NAME, provider->name,
+                        MOBILE_COL_PROVIDER, provider,
+                        -1);
+
+    country_iter = info->parent_iter;
+    info->parent_iter = &iter;
+    g_slist_foreach (provider->methods, add_one_method, info);
+    info->parent_iter = country_iter;
+}
+
+static void
 add_one_country (gpointer key, gpointer value, gpointer user_data)
 {
     GSList *providers = (GSList *) value;
     MobilePopulateInfo *info = (MobilePopulateInfo *) user_data;
-    GSList *iter;
-    GtkTreeIter country_iter;
+    GtkTreeIter iter;
 
     if (!provider_list_has_type (providers, info->provider_type))
         return;
 
-    gtk_tree_store_append (info->store, &country_iter, NULL);
-    gtk_tree_store_set (info->store, &country_iter,
+    gtk_tree_store_append (info->store, &iter, NULL);
+    gtk_tree_store_set (info->store, &iter,
                         MOBILE_COL_NAME, key,
-                        MOBILE_COL_DATA, NULL,
                         -1);
 
-    for (iter = providers; iter; iter = iter->next) {
-        NmnMobileProvider *provider = (NmnMobileProvider *) iter->data;
-        GtkTreeIter provider_iter;
-
-        if (provider->type == info->provider_type) {
-            gtk_tree_store_append (info->store, &provider_iter, &country_iter);
-            gtk_tree_store_set (info->store, &provider_iter,
-                                MOBILE_COL_NAME, provider->name,
-                                MOBILE_COL_DATA, provider,
-                                -1);
-        }
-    }
+    info->parent_iter = &iter;
+    g_slist_foreach (providers, add_one_provider, info);
 }
 
 static void
@@ -212,11 +271,11 @@ mobile_list_populate (NmnNewConnection *connection)
     if (priv->mobile_list_populated || !mobile_have_device (connection, &provider_type))
         return;
 
-    mobile_providers = nmn_mobile_providers_parse ();
+    mobile_providers = nmn_mobile_providers_parse (NULL);
     if (!mobile_providers)
         return;
 
-    store = gtk_tree_store_new (2, G_TYPE_STRING, NMN_TYPE_MOBILE_PROVIDER);
+    store = gtk_tree_store_new (3, G_TYPE_STRING, NMN_TYPE_MOBILE_PROVIDER, NMN_TYPE_MOBILE_ACCESS_METHOD);
 
     info.store = store;
     info.provider_type = provider_type;
@@ -247,17 +306,18 @@ mobile_tree_selection_changed (GtkTreeSelection *selection,
     NmnNewConnection *connection = (NmnNewConnection *) user_data;
     NmnNewConnectionPrivate *priv = GET_PRIVATE (connection);
     GtkTreeModel *model;
-    NmnMobileProvider *provider = NULL;
+    NmnMobileAccessMethod *method = NULL;
     GtkTreeIter iter;
 
     if (gtk_tree_selection_get_selected (selection, &model, &iter))
-        gtk_tree_model_get (model, &iter, MOBILE_COL_DATA, &provider, -1);
+        gtk_tree_model_get (model, &iter, MOBILE_COL_METHOD, &method, -1);
 
-    gtk_widget_set_sensitive (priv->mobile_save, provider != NULL);
+    gtk_widget_set_sensitive (priv->mobile_save, method != NULL);
 }
 
 static NMConnection *
-mobile_new_connection (NmnMobileProvider *provider)
+mobile_new_connection (NmnMobileProvider *provider,
+                       NmnMobileAccessMethod *method)
 {
     NMConnection *connection;
     NMSetting *type_setting;
@@ -267,15 +327,28 @@ mobile_new_connection (NmnMobileProvider *provider)
 
     connection = nm_connection_new ();
 
-    if (provider->type == NMN_PROVIDER_TYPE_GSM) {
+    if (method->type == NMN_MOBILE_ACCESS_METHOD_TYPE_GSM) {
         type_setting = nm_setting_gsm_new ();
         g_object_set (type_setting,
-                      NM_SETTING_GSM_NUMBER, "*99#",
-                      NM_SETTING_GSM_USERNAME, provider->username,
-                      NM_SETTING_GSM_PASSWORD, provider->password,
-                      NM_SETTING_GSM_APN, provider->apn,
+                      NM_SETTING_GSM_NUMBER,   "*99#",
+                      NM_SETTING_GSM_USERNAME, method->username,
+                      NM_SETTING_GSM_PASSWORD, method->password,
+                      NM_SETTING_GSM_APN,      method->gsm_apn,
                       NULL);
-    } else if (provider->type == NMN_PROVIDER_TYPE_CDMA) {
+
+        /* FIXME: Choose the network_id more intelligently */
+        if (g_slist_length (method->gsm_mcc_mnc) == 1) {
+            NmnGsmMccMnc *mcc_mnc = (NmnGsmMccMnc *) method->gsm_mcc_mnc->data;
+            char *network_id;
+
+            network_id = g_strconcat (mcc_mnc->mcc, mcc_mnc->mnc, NULL);
+            g_object_set (type_setting,
+                          NM_SETTING_GSM_NETWORK_ID, network_id,
+                          NULL);
+
+            g_free (network_id);
+        }
+    } else if (method->type == NMN_MOBILE_ACCESS_METHOD_TYPE_CDMA) {
         type_setting = nm_setting_cdma_new ();
         g_object_set (type_setting, NM_SETTING_CDMA_NUMBER, "#777", NULL);
     } else
@@ -283,13 +356,13 @@ mobile_new_connection (NmnMobileProvider *provider)
 
     nm_connection_add_setting (connection, type_setting);
 
-    if (provider->gateway || provider->dns) {
+    if (method->gateway || method->dns) {
         GSList *iter;
 
         setting = nm_setting_ip4_config_new ();
         g_object_set (setting, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL);
 
-        for (iter = provider->dns; iter; iter = iter->next) {
+        for (iter = method->dns; iter; iter = iter->next) {
             struct in_addr addr;
 
             if (inet_pton (AF_INET, (char *) iter->data, &addr) > 0)
@@ -297,8 +370,8 @@ mobile_new_connection (NmnMobileProvider *provider)
         }
 
         /* I'd rather not use the gateway from providers database */
-        /* if (provider->gateway) */
-        
+        /* if (method->gateway) */
+
         nm_connection_add_setting (connection, setting);
     }
 
@@ -333,7 +406,6 @@ mobile_new_connection (NmnMobileProvider *provider)
     return connection;
 }
 
-
 static void
 mobile_save_clicked (GtkButton *button, gpointer user_data)
 {
@@ -342,17 +414,25 @@ mobile_save_clicked (GtkButton *button, gpointer user_data)
     GtkTreeSelection *selection;
     GtkTreeModel *model;
     NmnMobileProvider *provider = NULL;
-    GtkTreeIter iter;
+    NmnMobileAccessMethod *method = NULL;
+    GtkTreeIter method_iter;
+    GtkTreeIter provider_iter;
 
     selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->mobile_list));
-    if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+    if (!gtk_tree_selection_get_selected (selection, &model, &method_iter))
         return;
 
-    gtk_tree_model_get (model, &iter, MOBILE_COL_DATA, &provider, -1);
-    if (provider) {
+    if (!gtk_tree_model_iter_parent (model, &provider_iter, &method_iter))
+        return;
+
+    gtk_tree_model_get (model, &method_iter, MOBILE_COL_METHOD, &method, -1);
+    gtk_tree_model_get (model, &provider_iter, MOBILE_COL_PROVIDER, &provider, -1);
+
+    if (provider && method) {
         NMConnection *connection;
 
-        connection = mobile_new_connection (provider);
+        connection = NULL;
+        connection = mobile_new_connection (provider, method);
         nmn_mobile_provider_unref (provider);
 
         if (connection) {



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