--- Makefile.am | 3 +- src/operator-settings.c | 292 +++++++++++++++++++++++++++++++++++++++++++++++ src/operator-settings.h | 37 ++++++ 3 files changed, 331 insertions(+), 1 deletions(-) create mode 100644 src/operator-settings.c create mode 100644 src/operator-settings.h
diff --git a/Makefile.am b/Makefile.am index 12b3c33..93e4d28 100644 --- a/Makefile.am +++ b/Makefile.am @@ -319,7 +319,8 @@ src_ofonod_SOURCES = $(gdbus_sources) $(builtin_sources) src/ofono.ver \ src/radio-settings.c src/stkutil.h src/stkutil.c \ src/nettime.c src/stkagent.c src/stkagent.h \ src/simfs.c src/simfs.h src/audio-settings.c \ - src/smsagent.c src/smsagent.h src/ctm.c + src/smsagent.c src/smsagent.h src/ctm.c \ + src/operator-settings.c src/operator-settings.h src_ofonod_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ @CAPNG_LIBS@ -ldl diff --git a/src/operator-settings.c b/src/operator-settings.c new file mode 100644 index 0000000..7b63d94 --- /dev/null +++ b/src/operator-settings.c @@ -0,0 +1,292 @@ +/* + * oFono - Open Source Telephony + * + * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <glib.h> + +#include "ofono.h" +#include "operator-settings.h" + +#define MAX_PROXY_NAME_LENGTH 255 + +void gprs_access_settings_free(struct gprs_access_settings *settings) +{ + if (settings == NULL) + return; + + g_free(settings->name); + g_free(settings->apn); + g_free(settings->username); + g_free(settings->password); + g_free(settings->proxy); + g_free(settings->mms_server); + g_free(settings->spn); + g_free(settings); +} + +static enum ofono_gprs_context_type string_to_gprs_context_type(const char *str) +{ + if (str) { + if (strcasecmp(str, "INTERNET") == 0) + return OFONO_GPRS_CONTEXT_TYPE_INTERNET; + if (strcasecmp(str, "MMS") == 0) + return OFONO_GPRS_CONTEXT_TYPE_MMS; + } + + return OFONO_GPRS_CONTEXT_TYPE_ANY; +} + +static gchar *cleanstr(const char *str) +{ + return g_strstrip(g_strdup(str)); +} + +/* + * Parse settings csv-file line. If MCC/MNC matches, return settings + * + * Settings file format: Comma separated fields (that cannot contain commas) of: + * MCC,MNC,SPN,type,UI name, APN, username, password, protocol,\ + * proxy IP address, proxy port, MMS server URL + * where type=INTERNET|MMS, protocol=ipv4|ipv6 + */ +static struct gprs_access_settings *parse_setting_line(const char *line, + const char *mcc, + const char *mnc) +{ + gchar **columns; + int count; + struct gprs_access_settings *entry = NULL; + + columns = g_strsplit(line, ",", 0); + count = g_strv_length(columns); + + /* mandatory values: mcc, mnc, spn, type, name, apn */ + if (count < 6) + goto finish; + + if (strcmp(mcc, columns[0]) != 0 || strcmp(mnc, columns[1]) != 0) + goto finish; + + entry = g_try_malloc0(sizeof(*entry)); + if (entry == NULL) + goto finish; + + entry->spn = cleanstr(columns[2]); + entry->type = string_to_gprs_context_type(columns[3]); + entry->name = cleanstr(columns[4]); + entry->apn = cleanstr(columns[5]); + + if (count > 6) + entry->username = cleanstr(columns[6]); + else + entry->username = g_strdup(""); + + if (count > 7) + entry->password = cleanstr(columns[7]); + else + entry->password = g_strdup(""); + + if (count > 8 && strcmp(columns[8], "ipv6") == 0) + entry->proto = OFONO_GPRS_PROTO_IPV6; + else + entry->proto = OFONO_GPRS_PROTO_IP; + + if (count > 9) { + gchar proxy[MAX_PROXY_NAME_LENGTH + 1]; + g_strlcpy(proxy, columns[9], MAX_PROXY_NAME_LENGTH); + + if (count > 10 && strlen(columns[10]) > 0) { + g_strlcat(proxy, ":", MAX_PROXY_NAME_LENGTH); + g_strlcat(proxy, columns[10], MAX_PROXY_NAME_LENGTH); + } + + entry->proxy = cleanstr(proxy); + } + + if (count > 11) + entry->mms_server = cleanstr(columns[11]); + +finish: + g_strfreev(columns); + return entry; +} + +/* + * Returns list of candidate settings matching mcc/mnc from operator + * settings file + */ +static GSList *read_settings_file(const char *filename, + const char *mcc, const char *mnc) +{ + GSList *entries = NULL; + FILE *f; + char *line = NULL; + size_t len = 0; + ssize_t read; + + if (filename == NULL || mcc == NULL || mnc == NULL) + return NULL; + + f = fopen(filename, "r"); + if (f == NULL) { + DBG("Error opening settings file %s", filename); + return NULL; + } + + while ((read = getline(&line, &len, f)) != -1) { + struct gprs_access_settings *entry; + entry = parse_setting_line(line, mcc, mnc); + if (entry != NULL) + entries = g_slist_append(entries, entry); + } + + free(line); + fclose(f); + + return entries; +} + +static gboolean is_match(struct gprs_access_settings *entry, + enum ofono_gprs_context_type type, + gchar *spn_casefold) +{ + gboolean ret = FALSE; + gchar *entryspn_casefold = NULL; + + if (entry->spn != NULL && strlen(entry->spn) > 0) + entryspn_casefold = g_utf8_casefold(entry->spn, -1); + + if (type == entry->type) { + if (spn_casefold != NULL) { + if (entryspn_casefold && + strcmp(spn_casefold, + entryspn_casefold) == 0) { + ret = TRUE; + } + } else { + ret = TRUE; + } + } + + g_free(entryspn_casefold); + return ret; +} + +/* + * Find best match from candidate settings based on type and SPN + * If there is no candidate matching SPN, take first one matching type. + */ +static GSList *match_entry(GSList * candidates, + enum ofono_gprs_context_type type, + const char *spn) +{ + GSList *ret = NULL; + GSList *lp = candidates; + gchar *spn_casefold = NULL; + + if (spn != NULL && strlen(spn) > 0) + spn_casefold = g_utf8_casefold(spn, -1); + + while (lp) { + struct gprs_access_settings *entry = lp->data; + if (is_match(entry, type, spn_casefold)) { + ret = lp; + break; + } + + lp = lp->next; + if (lp == NULL && spn_casefold != NULL) { + /* No SPN matches, retry with only type */ + g_free(spn_casefold); + spn_casefold = NULL; + lp = candidates; + } + } + + g_free(spn_casefold); + return ret; +} + +/* + * Returns GPRS context settings (internet and mms types) based on + * SIM provided MCC,MNC and Service Provider Name values. + * Operator settings for Internet and MMS access points are stored + * in CSV formatted files (*.csv) under $CONDIFDIR/operator-settings + */ +GSList *get_operator_settings(const char *mcc, const char *mnc, const char *spn) +{ + GSList *ret = NULL; + GSList *candidates = NULL; + GSList *match; + GDir *dir; + GSList *files = NULL, *lp; + const gchar *filename; + + dir = g_dir_open(CONFIGDIR "/" SETTING_FILE_DIR, 0, NULL); + if (dir == NULL) { + DBG("Error opening settings directory"); + return NULL; + } + + while ((filename = g_dir_read_name(dir)) != NULL) { + if (g_str_has_suffix(filename, ".csv")) { + gchar *fn = g_strjoin("/", CONFIGDIR, SETTING_FILE_DIR, + filename, NULL); + files = g_slist_append(files, fn); + } + } + + files = g_slist_sort(files, (GCompareFunc) g_strcmp0); + + for (lp = files; lp != NULL; lp = lp->next) { + GSList *entries; + gchar *fn; + fn = lp->data; + entries = read_settings_file(fn, mcc, mnc); + candidates = g_slist_concat(candidates, entries); + g_free(fn); + } + + g_slist_free(files); + g_dir_close(dir); + + match = match_entry(candidates, OFONO_GPRS_CONTEXT_TYPE_INTERNET, spn); + if (match != NULL) { + candidates = g_slist_remove_link(candidates, match); + ret = g_slist_concat(ret, match); + } + + match = match_entry(candidates, OFONO_GPRS_CONTEXT_TYPE_MMS, spn); + if (match != NULL) { + candidates = g_slist_remove_link(candidates, match); + ret = g_slist_concat(ret, match); + } + + g_slist_foreach(candidates, (GFunc) gprs_access_settings_free, NULL); + g_slist_free(candidates); + + return ret; +} diff --git a/src/operator-settings.h b/src/operator-settings.h new file mode 100644 index 0000000..95f3785 --- /dev/null +++ b/src/operator-settings.h @@ -0,0 +1,37 @@ +/* + * oFono - Open Source Telephony + * + * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies). + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#define SETTING_FILE_DIR "operator-settings" + +struct gprs_access_settings { + enum ofono_gprs_context_type type; + gchar *name; + gchar *apn; + gchar *username; + gchar *password; + enum ofono_gprs_proto proto; + gchar *proxy; + gchar *mms_server; + gchar *spn; +}; + +GSList *get_operator_settings(const char *mcc, const char *mnc, + const char *spn); +void gprs_access_settings_free(struct gprs_access_settings *settings); -- 1.7.1 _______________________________________________ ofono mailing list ofono@ofono.org http://lists.ofono.org/listinfo/ofono