summaryrefslogtreecommitdiffstats
path: root/src/phonebook.c
diff options
context:
space:
mode:
authorYang Gu <yang.gu@intel.com>2009-06-15 16:18:48 +0800
committerDenis Kenzior <denkenz@gmail.com>2009-06-16 16:38:17 -0500
commitf00af4527000c02dfe1aee4b6afeadef82bd4f65 (patch)
tree09a36dcff2d6000c0678b5d0d9ef1a22defa65e3 /src/phonebook.c
parentac4aeac3d633cfec448d4646cb9a1d332e0fdc8f (diff)
downloadofono-f00af4527000c02dfe1aee4b6afeadef82bd4f65.tar.bz2
Export phonebook as vCard 3.0 format
Diffstat (limited to 'src/phonebook.c')
-rw-r--r--src/phonebook.c318
1 files changed, 318 insertions, 0 deletions
diff --git a/src/phonebook.c b/src/phonebook.c
new file mode 100644
index 00000000..ae62286e
--- /dev/null
+++ b/src/phonebook.c
@@ -0,0 +1,318 @@
+/*
+ * oFono - GSM Telephony Stack for Linux
+ *
+ * Copyright (C) 2008-2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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
+
+#define _GNU_SOURCE
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <dbus/dbus.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include "ofono.h"
+
+#include "dbus-gsm.h"
+#include "modem.h"
+#include "driver.h"
+#include "common.h"
+
+
+#define PHONEBOOK_SERVICES_INTERFACE "org.ofono.Phonebook"
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define LEN_MAX 128
+#define TYPE_INTERNATIONAL 145
+
+struct phonebook_data {
+ struct ofono_phonebook_ops *ops;
+ DBusMessage *pending;
+ int storage_support_index; /* go through all supported storage */
+ int cached;
+ GString entries_vcard; /* entries with vcard 3.0 format */
+};
+
+static DBusMessage *export_entries_one_storage(DBusConnection *conn,
+ DBusMessage *msg, void *data);
+
+static const char *storage_support[] = { "\"SM\"", "\"ME\"", NULL };
+
+static struct phonebook_data *phonebook_create()
+{
+ struct phonebook_data *phonebook;
+ phonebook = g_try_new0(struct phonebook_data, 1);
+ return phonebook;
+}
+
+static void phonebook_destroy(gpointer data)
+{
+ struct ofono_modem *modem = data;
+ struct phonebook_data *phonebook = modem->phonebook;
+ g_free(phonebook);
+ modem->phonebook = NULL;
+}
+
+/* according to RFC 2425, the output string may need folding */
+static void vcard_printf(GString *str, const char *fmt, ...)
+{
+ char buf[1024];
+ va_list ap;
+ int len_temp, line_number, i;
+ unsigned int line_delimit = 75;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ line_number = strlen(buf) / line_delimit + 1;
+
+ for (i = 0; i < line_number; i++) {
+ len_temp = MIN(line_delimit, strlen(buf) - line_delimit * i);
+ g_string_append_len(str, buf + line_delimit * i, len_temp);
+ if (i != line_number - 1)
+ g_string_append(str, "\r\n ");
+ }
+
+ g_string_append(str, "\r\n");
+}
+
+/* According to RFC 2426, we need escape following characters:
+ * '\n', '\r', ';', ',', '\'.
+ */
+static void add_slash(char *dest, char *src, int len_max, int len)
+{
+ int i, j;
+
+ for (i = 0, j = 0; i < len && j < len_max; i++, j++) {
+ switch (src[i]) {
+ case '\n':
+ dest[j++] = '\\';
+ dest[j] = 'n';
+ break;
+ case '\r':
+ dest[j++] = '\\';
+ dest[j] = 'r';
+ break;
+ case '\\':
+ case ';':
+ case ',':
+ dest[j++] = '\\';
+ default:
+ dest[j] = src[i];
+ break;
+ }
+ }
+ dest[j] = 0;
+ return;
+}
+
+static void vcard_printf_number(GString *entries_vcard_pointer, int type,
+ char *number, int prefer)
+{
+ char *pref = "", *intl = "";
+ char buf[128];
+ if (prefer)
+ pref = "PREF,";
+ if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
+ intl = "+";
+
+ sprintf(buf, "TEL;TYPE=\%sVOICE:\%s\%s", pref, intl, number);
+ vcard_printf(entries_vcard_pointer, buf, number);
+}
+
+
+static void entry_to_vcard(GString *entries_vcard_pointer,
+ struct ofono_phonebook_entry *entry)
+{
+ char field[LEN_MAX];
+ vcard_printf(entries_vcard_pointer, "BEGIN:VCARD");
+ vcard_printf(entries_vcard_pointer, "VERSION:3.0");
+ add_slash(field, entry->text, LEN_MAX, strlen(entry->text));
+ vcard_printf(entries_vcard_pointer, "FN:%s", field);
+ vcard_printf_number(entries_vcard_pointer, entry->type,
+ entry->number, 1);
+ if (entry->group) {
+ add_slash(field, entry->group, LEN_MAX, strlen(entry->group));
+ vcard_printf(entries_vcard_pointer, "CATEGORIES:%s", field);
+ }
+ if (entry->adtype && entry->adnumber) {
+ vcard_printf_number(entries_vcard_pointer, entry->adtype,
+ entry->adnumber, 0);
+ }
+ if (entry->email) {
+ add_slash(field, entry->email, LEN_MAX, strlen(entry->email));
+ vcard_printf(entries_vcard_pointer,
+ "EMAIL;TYPE=INTERNET:%s", field);
+ }
+ if (entry->sip_uri) {
+ add_slash(field, entry->sip_uri, LEN_MAX,
+ strlen(entry->sip_uri));
+ vcard_printf(entries_vcard_pointer, "IMPP;TYPE=SIP:%s", field);
+ }
+ vcard_printf(entries_vcard_pointer, "END:VCARD");
+ vcard_printf(entries_vcard_pointer, "");
+}
+
+static DBusMessage *generate_export_entries_reply(struct ofono_modem *modem)
+{
+ struct phonebook_data *phonebook = modem->phonebook;
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusConnection *conn = dbus_gsm_connection();
+
+ reply = dbus_message_new_method_return(phonebook->pending);
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+ &(phonebook->entries_vcard));
+ g_dbus_send_message(conn, reply);
+ return NULL;
+}
+
+static void export_entries_one_storage_cb(const struct ofono_error *error,
+ int num_entries, const struct ofono_phonebook_entry *entries, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct phonebook_data *phonebook = modem->phonebook;
+ DBusConnection *conn = dbus_gsm_connection();
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ ofono_error("export_entries_one_storage_cb with %s failed",
+ storage_support[phonebook->storage_support_index]);
+ else {
+ int num = 0;
+ GString *entries_vcard_pointer = &(phonebook->entries_vcard);
+ for (num = 0; num < num_entries; num++)
+ entry_to_vcard(entries_vcard_pointer,
+ (struct ofono_phonebook_entry *)&entries[num]);
+ }
+
+ phonebook->storage_support_index++;
+ export_entries_one_storage(conn, phonebook->pending, modem);
+ return;
+}
+
+static DBusMessage *export_entries_one_storage(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct phonebook_data *phonebook = modem->phonebook;
+
+ if (storage_support[phonebook->storage_support_index] != NULL)
+ phonebook->ops->export_entries(modem,
+ (char *)storage_support[phonebook->storage_support_index],
+ export_entries_one_storage_cb, modem);
+ else {
+ phonebook->cached = 1;
+ generate_export_entries_reply(modem);
+ dbus_message_unref(phonebook->pending);
+ phonebook->pending = NULL;
+ }
+
+ return NULL;
+}
+
+static DBusMessage *export_entries(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct phonebook_data *phonebook = modem->phonebook;
+
+ if (phonebook->pending) {
+ DBusMessage *reply;
+ reply = dbus_gsm_busy(phonebook->pending);
+ g_dbus_send_message(conn, reply);
+ return NULL;
+ }
+ phonebook->pending = dbus_message_ref(msg);
+
+ if (phonebook->cached) {
+ generate_export_entries_reply(modem);
+ dbus_message_unref(phonebook->pending);
+ phonebook->pending = NULL;
+ return NULL;
+ }
+
+ g_string_set_size(&(phonebook->entries_vcard), 0);
+ phonebook->storage_support_index = 0;
+ export_entries_one_storage(conn, msg, data);
+ return NULL;
+}
+
+static GDBusMethodTable phonebook_methods[] = {
+ { "ExportEntries", "", "s", export_entries,
+ G_DBUS_METHOD_FLAG_ASYNC },
+ { }
+};
+
+static GDBusSignalTable phonebook_signals[] = {
+ { }
+};
+
+int ofono_phonebook_register(struct ofono_modem *modem,
+ struct ofono_phonebook_ops *ops)
+{
+ DBusConnection *conn = dbus_gsm_connection();
+
+ if (modem == NULL)
+ return -1;
+
+ if (ops == NULL)
+ return -1;
+
+ modem->phonebook = phonebook_create();
+
+ if (modem->phonebook == NULL)
+ return -1;
+
+ modem->phonebook->ops = ops;
+
+ if (!g_dbus_register_interface(conn, modem->path,
+ PHONEBOOK_SERVICES_INTERFACE,
+ phonebook_methods, phonebook_signals,
+ NULL, modem, phonebook_destroy)) {
+ ofono_error("Could not register Phonebook %s", modem->path);
+
+ phonebook_destroy(modem->phonebook);
+
+ return -1;
+ }
+
+ modem_add_interface(modem, PHONEBOOK_SERVICES_INTERFACE);
+ return 0;
+}
+
+void ofono_phonebook_unregister(struct ofono_modem *modem)
+{
+ DBusConnection *conn = dbus_gsm_connection();
+
+ if (modem->phonebook == NULL)
+ return;
+
+ modem_remove_interface(modem, PHONEBOOK_SERVICES_INTERFACE);
+ g_dbus_unregister_interface(conn, modem->path,
+ PHONEBOOK_SERVICES_INTERFACE);
+}