[evolution-data-server] Bug 443716 - Move evolution-addressbook-export to e-d-s
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 443716 - Move evolution-addressbook-export to e-d-s
- Date: Fri, 24 Jun 2016 10:21:45 +0000 (UTC)
commit 63b603a2ac3183fb0854a534da7c077a38e11e93
Author: Milan Crha <mcrha redhat com>
Date: Fri Jun 24 12:20:37 2016 +0200
Bug 443716 - Move evolution-addressbook-export to e-d-s
Makefile.am | 1 +
configure.ac | 6 +
po/POTFILES.in | 1 +
tools/Makefile.am | 5 +
tools/addressbook-export/Makefile.am | 41 +
tools/addressbook-export/addressbook-export.c | 1001 +++++++++++++++++++++++++
tools/addressbook-export/csv2vcard.in | 234 ++++++
7 files changed, 1289 insertions(+), 0 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 96e661b..b9814bf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,6 +24,7 @@ SUBDIRS = \
calendar \
modules \
services \
+ tools \
tests \
art \
po \
diff --git a/configure.ac b/configure.ac
index c76b172..f629e40 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1706,6 +1706,9 @@ AC_SUBST(privincludedir)
privlibdir='${libdir}'/evolution-data-server
AC_SUBST(privlibdir)
+privlibexecdir='${libexecdir}'/evolution-data-server
+AC_SUBST(privlibexecdir)
+
if test "$os_win32" = yes; then
dnl On Win32 there is no "rpath" mechanism. We install the private
dnl shared libraries in $libdir, meaning the DLLs will actually be in
@@ -1919,6 +1922,9 @@ services/evolution-addressbook-factory/Makefile
services/evolution-calendar-factory/Makefile
services/evolution-source-registry/Makefile
services/evolution-user-prompter/Makefile
+tools/Makefile
+tools/addressbook-export/Makefile
+tools/addressbook-export/csv2vcard
tests/Makefile
tests/libedata-book/Makefile
tests/libebook/Makefile
diff --git a/po/POTFILES.in b/po/POTFILES.in
index a01d86c..7252423 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -240,3 +240,4 @@ services/evolution-calendar-factory/evolution-calendar-factory.c
services/evolution-source-registry/evolution-source-registry.c
services/evolution-user-prompter/evolution-user-prompter.c
services/evolution-user-prompter/prompt-user-gtk.c
+tools/addressbook-export/addressbook-export.c
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..bfd9558
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = \
+ addressbook-export \
+ $(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/tools/addressbook-export/Makefile.am b/tools/addressbook-export/Makefile.am
new file mode 100644
index 0000000..1fa1802
--- /dev/null
+++ b/tools/addressbook-export/Makefile.am
@@ -0,0 +1,41 @@
+privlibexec_SCRIPTS = csv2vcard
+
+privlibexec_PROGRAMS = addressbook-export
+
+addressbook_export_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DG_LOG_DOMAIN=\"addressbook-export\" \
+ -I$(top_srcdir) \
+ -I$(top_builddir) \
+ -DLOCALEDIR=\""$(localedir)"\" \
+ -DPREFIX=\""$(prefix)"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/addressbook \
+ -I$(top_builddir) \
+ -I$(top_builddir)/addressbook \
+ $(EVOLUTION_ADDRESSBOOK_CFLAGS) \
+ $(CODE_COVERAGE_CFLAGS)
+
+addressbook_export_SOURCES = \
+ addressbook-export.c
+
+addressbook_export_LDADD = \
+ $(top_builddir)/addressbook/libebook/libebook-1.2.la \
+ $(top_builddir)/addressbook/libebook-contacts/libebook-contacts-1.2.la \
+ $(top_builddir)/libedataserver/libedataserver-1.2.la \
+ $(EVOLUTION_ADDRESSBOOK_LIBS)
+
+addressbook_export_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(CODE_COVERAGE_LDFLAGS)
+
+if OS_WIN32
+addressbook_export_LDFLAGS += -mwindows
+endif
+
+EXTRA_DIST = $(privlibexec_SCRIPTS)
+
+-include $(top_srcdir)/git.mk
diff --git a/tools/addressbook-export/addressbook-export.c b/tools/addressbook-export/addressbook-export.c
new file mode 100644
index 0000000..c5bf6fc
--- /dev/null
+++ b/tools/addressbook-export/addressbook-export.c
@@ -0,0 +1,1001 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License 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 Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Gilbert Fang <gilbert fang sun com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+
+#include <libebook/libebook.h>
+#include <libedataserver/libedataserver.h>
+
+#define COMMA_SEPARATOR ","
+
+#define SUCCESS 0
+#define FAILED -1
+
+#define ACTION_NOTHING 0
+#define ACTION_LIST_FOLDERS 1
+#define ACTION_LIST_CARDS 2
+
+#define DEFAULT_SIZE_NUMBER 100
+
+struct _ActionContext {
+ GMainLoop *main_loop;
+ guint action_type;
+
+ ESourceRegistry *registry;
+ const gchar *output_file;
+
+ /* for cards only */
+ gint IsCSV;
+ gint IsVCard;
+ const gchar *addressbook_source_uid;
+};
+
+typedef struct _ActionContext ActionContext;
+
+static void
+action_list_folders_init (ActionContext *p_actctx)
+{
+ ESourceRegistry *registry;
+ GList *list, *iter;
+ FILE *outputfile = NULL;
+ const gchar *extension_name;
+
+ registry = p_actctx->registry;
+
+ if (p_actctx->output_file != NULL) {
+ if (!(outputfile = g_fopen (p_actctx->output_file, "w"))) {
+ g_warning (_("Can not open file"));
+ exit (-1);
+ }
+ }
+
+ extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+ list = e_source_registry_list_sources (registry, extension_name);
+
+ for (iter = list; iter != NULL; iter = g_list_next (iter)) {
+ EClient *client;
+ EBookClient *book_client;
+ EBookQuery *query;
+ ESource *source;
+ GSList *contacts;
+ const gchar *display_name;
+ const gchar *uid;
+ gchar *query_str;
+ GError *error = NULL;
+
+ source = E_SOURCE (iter->data);
+
+ client = e_book_client_connect_sync (source, 30, NULL, &error);
+
+ /* Sanity check. */
+ g_warn_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (error != NULL) {
+ g_warning (
+ _("Failed to open client '%s': %s"),
+ e_source_get_display_name (source),
+ error->message);
+ g_error_free (error);
+ continue;
+ }
+
+ book_client = E_BOOK_CLIENT (client);
+
+ query = e_book_query_any_field_contains ("");
+ query_str = e_book_query_to_string (query);
+ e_book_query_unref (query);
+
+ e_book_client_get_contacts_sync (
+ book_client, query_str, &contacts, NULL, NULL);
+
+ display_name = e_source_get_display_name (source);
+ uid = e_source_get_uid (source);
+
+ if (outputfile)
+ fprintf (
+ outputfile, "\"%s\",\"%s\",%d\n",
+ uid, display_name, g_slist_length (contacts));
+ else
+ printf (
+ "\"%s\",\"%s\",%d\n",
+ uid, display_name, g_slist_length (contacts));
+
+ g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+ g_slist_free (contacts);
+
+ g_object_unref (book_client);
+ }
+
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+
+ if (outputfile)
+ fclose (outputfile);
+}
+
+typedef enum _CARD_FORMAT CARD_FORMAT;
+typedef enum _DeliveryAddressField DeliveryAddressField;
+typedef enum _EContactFieldCSV EContactFieldCSV;
+typedef struct _EContactCSVFieldData EContactCSVFieldData;
+
+enum _CARD_FORMAT
+{
+ CARD_FORMAT_CSV,
+ CARD_FORMAT_VCARD
+};
+
+enum _DeliveryAddressField
+{
+ DELIVERY_ADDRESS_STREET,
+ DELIVERY_ADDRESS_EXT,
+ DELIVERY_ADDRESS_LOCALITY,
+ DELIVERY_ADDRESS_REGION,
+ DELIVERY_ADDRESS_CODE,
+ DELIVERY_ADDRESS_COUNTRY
+};
+
+enum _EContactFieldCSV
+{
+ E_CONTACT_CSV_FILE_AS,
+ E_CONTACT_CSV_FULL_NAME,
+ E_CONTACT_CSV_EMAIL_1,
+ E_CONTACT_CSV_EMAIL_2,
+ E_CONTACT_CSV_EMAIL_3,
+ E_CONTACT_CSV_EMAIL_4,
+ E_CONTACT_CSV_PHONE_PRIMARY,
+ E_CONTACT_CSV_PHONE_ASSISTANT,
+ E_CONTACT_CSV_PHONE_BUSINESS,
+ E_CONTACT_CSV_PHONE_CALLBACK,
+ E_CONTACT_CSV_PHONE_COMPANY,
+ E_CONTACT_CSV_PHONE_HOME,
+ E_CONTACT_CSV_ORG,
+ /*E_CONTACT_CSV_ADDRESS_BUSINESS, */
+ E_CONTACT_CSV_ADDRESS_BUSINESS_STREET,
+ E_CONTACT_CSV_ADDRESS_BUSINESS_EXT,
+ E_CONTACT_CSV_ADDRESS_BUSINESS_CITY,
+ E_CONTACT_CSV_ADDRESS_BUSINESS_REGION,
+ E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE,
+ E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY,
+ /*E_CONTACT_CSV_ADDRESS_HOME, */
+ E_CONTACT_CSV_ADDRESS_HOME_STREET,
+ E_CONTACT_CSV_ADDRESS_HOME_EXT,
+ E_CONTACT_CSV_ADDRESS_HOME_CITY,
+ E_CONTACT_CSV_ADDRESS_HOME_REGION,
+ E_CONTACT_CSV_ADDRESS_HOME_POSTCODE,
+ E_CONTACT_CSV_ADDRESS_HOME_COUNTRY,
+ E_CONTACT_CSV_PHONE_MOBILE,
+ E_CONTACT_CSV_PHONE_CAR,
+ E_CONTACT_CSV_PHONE_BUSINESS_FAX,
+ E_CONTACT_CSV_PHONE_HOME_FAX,
+ E_CONTACT_CSV_PHONE_BUSINESS_2,
+ E_CONTACT_CSV_PHONE_HOME_2,
+ E_CONTACT_CSV_PHONE_ISDN,
+ E_CONTACT_CSV_PHONE_OTHER,
+ E_CONTACT_CSV_PHONE_OTHER_FAX,
+ E_CONTACT_CSV_PHONE_PAGER,
+ E_CONTACT_CSV_PHONE_RADIO,
+ E_CONTACT_CSV_PHONE_TELEX,
+ E_CONTACT_CSV_PHONE_TTYTDD,
+ /*E_CONTACT_CSV_ADDRESS_OTHER, */
+ E_CONTACT_CSV_ADDRESS_OTHER_STREET,
+ E_CONTACT_CSV_ADDRESS_OTHER_EXT,
+ E_CONTACT_CSV_ADDRESS_OTHER_CITY,
+ E_CONTACT_CSV_ADDRESS_OTHER_REGION,
+ E_CONTACT_CSV_ADDRESS_OTHER_POSTCODE,
+ E_CONTACT_CSV_ADDRESS_OTHER_COUNTRY,
+ E_CONTACT_CSV_HOMEPAGE_URL,
+ E_CONTACT_CSV_ORG_UNIT,
+ E_CONTACT_CSV_OFFICE,
+ E_CONTACT_CSV_TITLE,
+ E_CONTACT_CSV_ROLE,
+ E_CONTACT_CSV_MANAGER,
+ E_CONTACT_CSV_ASSISTANT,
+ E_CONTACT_CSV_NICKNAME,
+ E_CONTACT_CSV_SPOUSE,
+ E_CONTACT_CSV_NOTE,
+ E_CONTACT_CSV_CALENDAR_URI,
+ E_CONTACT_CSV_FREEBUSY_URL,
+ /*E_CONTACT_CSV_ANNIVERSARY, */
+ E_CONTACT_CSV_ANNIVERSARY_YEAR,
+ E_CONTACT_CSV_ANNIVERSARY_MONTH,
+ E_CONTACT_CSV_ANNIVERSARY_DAY,
+ /*E_CONTACT_CSV_BIRTH_DATE, */
+ E_CONTACT_CSV_BIRTH_DATE_YEAR,
+ E_CONTACT_CSV_BIRTH_DATE_MONTH,
+ E_CONTACT_CSV_BIRTH_DATE_DAY,
+ E_CONTACT_CSV_MAILER,
+ E_CONTACT_CSV_NAME_OR_ORG,
+ E_CONTACT_CSV_CATEGORIES,
+ E_CONTACT_CSV_FAMILY_NAME,
+ E_CONTACT_CSV_GIVEN_NAME,
+ E_CONTACT_CSV_WANTS_HTML,
+ E_CONTACT_CSV_IS_LIST,
+ E_CONTACT_CSV_LAST
+};
+
+typedef enum {
+ DT_STRING,
+ DT_BOOLEAN
+} EContactCSVDataType;
+
+struct _EContactCSVFieldData
+{
+ gint csv_field;
+ gint contact_field;
+ const gchar *csv_name;
+ EContactCSVDataType data_type;
+};
+
+#define NOMAP -1
+static EContactCSVFieldData csv_field_data[] = {
+ {E_CONTACT_CSV_FILE_AS, E_CONTACT_FILE_AS, "", DT_STRING},
+ {E_CONTACT_CSV_FULL_NAME, E_CONTACT_CSV_FULL_NAME, "", DT_STRING},
+ {E_CONTACT_CSV_EMAIL_1, E_CONTACT_EMAIL_1, "", DT_STRING},
+ {E_CONTACT_CSV_EMAIL_2, E_CONTACT_EMAIL_2, "", DT_STRING},
+ {E_CONTACT_CSV_EMAIL_3, E_CONTACT_EMAIL_3, "", DT_STRING},
+ {E_CONTACT_CSV_EMAIL_4, E_CONTACT_EMAIL_4, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_PRIMARY, E_CONTACT_PHONE_PRIMARY, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_ASSISTANT, E_CONTACT_PHONE_ASSISTANT, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_BUSINESS, E_CONTACT_PHONE_BUSINESS, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_CALLBACK, E_CONTACT_PHONE_CALLBACK, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_COMPANY, E_CONTACT_PHONE_COMPANY, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_HOME, E_CONTACT_PHONE_HOME, "", DT_STRING},
+ {E_CONTACT_CSV_ORG, E_CONTACT_ORG, "", DT_STRING},
+ /*E_CONTACT_CSV_ADDRESS_BUSINESS, */
+ {E_CONTACT_CSV_ADDRESS_BUSINESS_STREET, NOMAP, "Business Address", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_BUSINESS_EXT, NOMAP, "Business Address2", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_BUSINESS_CITY, NOMAP, "Business Address City", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_BUSINESS_REGION, NOMAP, "Business Address State", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE, NOMAP, "Business Address PostCode", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY, NOMAP, "Business Address Country", DT_STRING},
+ /*E_CONTACT_CSV_ADDRESS_HOME, */
+ {E_CONTACT_CSV_ADDRESS_HOME_STREET, NOMAP, "Home Address", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_HOME_EXT, NOMAP, "Home Address2", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_HOME_CITY, NOMAP, "Home Address City", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_HOME_REGION, NOMAP, "Home Address State", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_HOME_POSTCODE, NOMAP, "Home Address PostCode", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_HOME_COUNTRY, NOMAP, "Home Address Country", DT_STRING},
+ {E_CONTACT_CSV_PHONE_MOBILE, E_CONTACT_PHONE_MOBILE, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_CAR, E_CONTACT_PHONE_CAR, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_BUSINESS_FAX, E_CONTACT_PHONE_BUSINESS_FAX, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_HOME_FAX, E_CONTACT_PHONE_HOME_FAX, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_BUSINESS_2, E_CONTACT_PHONE_BUSINESS_2, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_HOME_2, E_CONTACT_PHONE_HOME_2, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_ISDN, E_CONTACT_PHONE_ISDN, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_OTHER, E_CONTACT_PHONE_OTHER, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_OTHER_FAX, E_CONTACT_PHONE_OTHER_FAX, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_PAGER, E_CONTACT_PHONE_PAGER, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_RADIO, E_CONTACT_PHONE_RADIO, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_TELEX, E_CONTACT_PHONE_TELEX, "", DT_STRING},
+ {E_CONTACT_CSV_PHONE_TTYTDD, E_CONTACT_PHONE_TTYTDD, "", DT_STRING},
+ /*E_CONTACT_CSV_ADDRESS_OTHER, */
+ {E_CONTACT_CSV_ADDRESS_OTHER_STREET, NOMAP, "Other Address", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_OTHER_EXT, NOMAP, "Other Address2", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_OTHER_CITY, NOMAP, "Other Address City", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_OTHER_REGION, NOMAP, "Other Address State", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_OTHER_POSTCODE, NOMAP, "Other Address PostCode", DT_STRING},
+ {E_CONTACT_CSV_ADDRESS_OTHER_COUNTRY, NOMAP, "Other Address Country", DT_STRING},
+ {E_CONTACT_CSV_HOMEPAGE_URL, E_CONTACT_HOMEPAGE_URL, "", DT_STRING},
+ {E_CONTACT_CSV_ORG_UNIT, E_CONTACT_ORG_UNIT, "", DT_STRING},
+ {E_CONTACT_CSV_OFFICE, E_CONTACT_OFFICE, "", DT_STRING},
+ {E_CONTACT_CSV_TITLE, E_CONTACT_TITLE, "", DT_STRING},
+ {E_CONTACT_CSV_ROLE, E_CONTACT_ROLE, "", DT_STRING},
+ {E_CONTACT_CSV_MANAGER, E_CONTACT_MANAGER, "", DT_STRING},
+ {E_CONTACT_CSV_ASSISTANT, E_CONTACT_ASSISTANT, "", DT_STRING},
+ {E_CONTACT_CSV_NICKNAME, E_CONTACT_NICKNAME, "", DT_STRING},
+ {E_CONTACT_CSV_SPOUSE, E_CONTACT_SPOUSE, "", DT_STRING},
+ {E_CONTACT_CSV_NOTE, E_CONTACT_NOTE, "", DT_STRING},
+ {E_CONTACT_CSV_CALENDAR_URI, E_CONTACT_CALENDAR_URI, "", DT_STRING},
+ {E_CONTACT_CSV_FREEBUSY_URL, E_CONTACT_FREEBUSY_URL, "", DT_STRING},
+ /*E_CONTACT_ANNIVERSARY, */
+ {E_CONTACT_CSV_ANNIVERSARY_YEAR, NOMAP, "Anniversary Year", DT_STRING},
+ {E_CONTACT_CSV_ANNIVERSARY_MONTH, NOMAP, "Anniversary Month", DT_STRING},
+ {E_CONTACT_CSV_ANNIVERSARY_DAY, NOMAP, "Anniversary Day", DT_STRING},
+ /*E_CONTACT_BIRTH_DATE, */
+ {E_CONTACT_CSV_BIRTH_DATE_YEAR, NOMAP, "Birth Year", DT_STRING},
+ {E_CONTACT_CSV_BIRTH_DATE_MONTH, NOMAP, "Birth Month", DT_STRING},
+ {E_CONTACT_CSV_BIRTH_DATE_DAY, NOMAP, "Birth Day", DT_STRING},
+ {E_CONTACT_CSV_MAILER, E_CONTACT_MAILER, "", DT_STRING},
+ {E_CONTACT_CSV_NAME_OR_ORG, E_CONTACT_NAME_OR_ORG, "", DT_STRING},
+ {E_CONTACT_CSV_CATEGORIES, E_CONTACT_CATEGORIES, "", DT_STRING},
+ {E_CONTACT_CSV_FAMILY_NAME, E_CONTACT_FAMILY_NAME, "", DT_STRING},
+ {E_CONTACT_CSV_GIVEN_NAME, E_CONTACT_GIVEN_NAME, "", DT_STRING},
+ {E_CONTACT_CSV_WANTS_HTML, E_CONTACT_WANTS_HTML, "", DT_BOOLEAN},
+ {E_CONTACT_CSV_IS_LIST, E_CONTACT_IS_LIST, "", DT_BOOLEAN},
+ {E_CONTACT_CSV_LAST, NOMAP, "", DT_STRING}
+
+};
+
+static GSList *pre_defined_fields;
+
+static gchar *
+escape_string (gchar *orig)
+{
+ const guchar *p;
+ gchar *dest;
+ gchar *q;
+
+ if (orig == NULL)
+ return g_strdup ("\"\"");
+
+ p = (guchar *) orig;
+ /* Each source byte needs maximally two destination chars (\n), and the extra 2 is for the leading
and trailing '"' */
+ q = dest = g_malloc (strlen (orig) * 2 + 1 + 2);
+
+ *q++ = '\"';
+ while (*p)
+ {
+ switch (*p)
+ {
+ case '\n':
+ *q++ = '\\';
+ *q++ = 'n';
+ break;
+ case '\r':
+ *q++ = '\\';
+ *q++ = 'r';
+ break;
+ case '\\':
+ *q++ = '\\';
+ *q++ = '\\';
+ break;
+ case '"':
+ *q++ = '"';
+ *q++ = '"';
+ break;
+ default:
+ *q++ = *p;
+ }
+ p++;
+ }
+
+ *q++ = '\"';
+ *q = 0;
+
+ return dest;
+}
+
+static gchar *
+check_null_pointer (gchar *orig)
+{
+ gchar *result;
+ if (orig == NULL)
+ result = g_strdup ("");
+ else
+ result = g_strdup (orig);
+ return result;
+}
+
+static gchar *
+delivery_address_get_sub_field (const EContactAddress *address,
+ DeliveryAddressField sub_field)
+{
+ gchar *sub_field_value;
+ gchar *str_temp, *str_temp_a;
+ if (address != NULL) {
+ switch (sub_field) {
+ case DELIVERY_ADDRESS_STREET:
+ str_temp_a = check_null_pointer (address->po);
+ str_temp = check_null_pointer (address->street);
+ sub_field_value = g_strdup_printf ("%s %s", str_temp_a, str_temp);
+ g_free (str_temp);
+ g_free (str_temp_a);
+ break;
+ case DELIVERY_ADDRESS_EXT:
+ sub_field_value = check_null_pointer (address->ext);
+ break;
+ case DELIVERY_ADDRESS_LOCALITY:
+ sub_field_value = check_null_pointer (address->locality);
+ break;
+ case DELIVERY_ADDRESS_REGION:
+ sub_field_value = check_null_pointer (address->region);
+ break;
+ case DELIVERY_ADDRESS_CODE:
+ sub_field_value = check_null_pointer (address->code);
+ break;
+ case DELIVERY_ADDRESS_COUNTRY:
+ sub_field_value = check_null_pointer (address->country);
+ break;
+ default:
+ sub_field_value = g_strdup ("");
+ }
+ } else {
+ sub_field_value = g_strdup ("");
+ }
+ return sub_field_value;
+}
+
+static gint
+e_contact_csv_get_contact_field (EContactFieldCSV csv_field)
+{
+ return csv_field_data[csv_field].contact_field;
+}
+
+static EContactCSVDataType
+e_contact_csv_get_data_type (EContactFieldCSV csv_field)
+{
+ return csv_field_data[csv_field].data_type;
+}
+
+static gchar *
+e_contact_csv_get_name (EContactFieldCSV csv_field)
+{
+ gint contact_field;
+ gchar *name;
+ gchar *quoted_name;
+
+ contact_field = e_contact_csv_get_contact_field (csv_field);
+
+ if (contact_field != NOMAP) {
+ name = g_strdup (e_contact_field_name (contact_field));
+ } else {
+ name = g_strdup (csv_field_data[csv_field].csv_name);
+ }
+ quoted_name = escape_string (name);
+ g_free (name);
+ return quoted_name;
+}
+
+static gchar *
+e_contact_csv_get (EContact *contact,
+ EContactFieldCSV csv_field)
+{
+ gint contact_field;
+ gchar *field_value;
+ gchar *quoted_field_value;
+
+ EContactAddress *delivery_address = NULL;
+ EContactDate *date;
+
+ contact_field = e_contact_csv_get_contact_field (csv_field);
+
+ if (contact_field != NOMAP) {
+ field_value = e_contact_get (contact, contact_field);
+ if (e_contact_csv_get_data_type (csv_field) == DT_BOOLEAN) {
+ field_value = g_strdup ((GPOINTER_TO_INT (field_value)) ? "TRUE" : "FALSE");
+ }
+ } else {
+ switch (csv_field) {
+ case E_CONTACT_CSV_ADDRESS_HOME_STREET:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_STREET);
+ break;
+ case E_CONTACT_CSV_ADDRESS_HOME_EXT:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
+ field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_EXT);
+ break;
+ case E_CONTACT_CSV_ADDRESS_HOME_CITY:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_LOCALITY);
+ break;
+ case E_CONTACT_CSV_ADDRESS_HOME_REGION:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_REGION);
+ break;
+ case E_CONTACT_CSV_ADDRESS_HOME_POSTCODE:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_CODE);
+ break;
+ case E_CONTACT_CSV_ADDRESS_HOME_COUNTRY:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_HOME);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_COUNTRY);
+ break;
+ case E_CONTACT_CSV_ADDRESS_BUSINESS_STREET:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_STREET);
+ break;
+ case E_CONTACT_CSV_ADDRESS_BUSINESS_EXT:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
+ field_value = delivery_address_get_sub_field (delivery_address, DELIVERY_ADDRESS_EXT);
+ break;
+ case E_CONTACT_CSV_ADDRESS_BUSINESS_CITY:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_LOCALITY);
+ break;
+ case E_CONTACT_CSV_ADDRESS_BUSINESS_REGION:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_REGION);
+ break;
+ case E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_CODE);
+ break;
+ case E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY:
+ delivery_address = e_contact_get (contact, E_CONTACT_ADDRESS_WORK);
+ field_value = delivery_address_get_sub_field (delivery_address,
DELIVERY_ADDRESS_COUNTRY);
+ break;
+ case E_CONTACT_CSV_BIRTH_DATE_YEAR:
+ date = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
+ if (date) {
+ field_value = g_strdup_printf ("%04d", date->year);
+ e_contact_date_free (date);
+ }
+ else {
+ field_value = g_strdup ("");
+ }
+ break;
+
+ case E_CONTACT_CSV_BIRTH_DATE_MONTH:
+ date = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
+ if (date) {
+ field_value = g_strdup_printf ("%04d", date->month);
+ e_contact_date_free (date);
+ }
+ else {
+ field_value = g_strdup ("");
+ }
+ break;
+
+ case E_CONTACT_CSV_BIRTH_DATE_DAY:
+ date = e_contact_get (contact, E_CONTACT_BIRTH_DATE);
+ if (date) {
+ field_value = g_strdup_printf ("%04d", date->day);
+ e_contact_date_free (date);
+ }
+ else {
+ field_value = g_strdup ("");
+ }
+ break;
+
+ default:
+ field_value = g_strdup ("");
+ }
+ }
+
+ /*checking to avoid the NULL pointer */
+ if (field_value == NULL)
+ field_value = g_strdup ("");
+
+ quoted_field_value = escape_string (field_value);
+ g_free (field_value);
+
+ if (delivery_address)
+ e_contact_address_free (delivery_address);
+
+ return quoted_field_value;
+}
+
+static gchar *
+e_contact_csv_get_header_line (GSList *csv_all_fields)
+{
+
+ guint field_number;
+ gint csv_field;
+ gchar **field_name_array;
+ gchar *header_line;
+
+ gint loop_counter;
+
+ field_number = g_slist_length (csv_all_fields);
+ field_name_array = g_new0 (gchar *, field_number + 1);
+
+ for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
+ csv_field = GPOINTER_TO_INT (g_slist_nth_data (csv_all_fields, loop_counter));
+ *(field_name_array + loop_counter) = e_contact_csv_get_name (csv_field);
+ }
+
+ header_line = g_strjoinv (COMMA_SEPARATOR, field_name_array);
+
+ for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
+ g_free (*(field_name_array + loop_counter));
+ }
+ g_free (field_name_array);
+
+ return header_line;
+
+}
+
+static gchar *
+e_contact_to_csv (EContact *contact,
+ GSList *csv_all_fields)
+{
+ guint field_number;
+ gint csv_field;
+ gchar **field_value_array;
+ gchar *aline;
+
+ gint loop_counter;
+
+ field_number = g_slist_length (csv_all_fields);
+ field_value_array = g_new0 (gchar *, field_number + 1);
+
+ for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
+ csv_field = GPOINTER_TO_INT (g_slist_nth_data (csv_all_fields, loop_counter));
+ *(field_value_array + loop_counter) = e_contact_csv_get (contact, csv_field);
+ }
+
+ aline = g_strjoinv (COMMA_SEPARATOR, field_value_array);
+
+ for (loop_counter = 0; loop_counter < field_number; loop_counter++) {
+ g_free (*(field_value_array + loop_counter));
+ }
+ g_free (field_value_array);
+
+ return aline;
+
+}
+
+static gchar *
+e_contact_get_csv (EContact *contact,
+ GSList *csv_all_fields)
+{
+ gchar *aline;
+ GList *emails;
+ guint n_emails;
+ gchar *full_name;
+
+ emails = e_contact_get_attributes (contact, E_CONTACT_EMAIL);
+ n_emails = g_list_length (emails);
+ full_name = e_contact_get (contact, E_CONTACT_FULL_NAME);
+ if (n_emails > 4)
+ g_warning ("%s: only 4 out of %i emails have been exported", full_name, n_emails);
+ g_free (full_name);
+ g_list_free_full (emails, (GDestroyNotify) e_vcard_attribute_free);
+
+ aline = e_contact_to_csv (contact, csv_all_fields);
+ return aline;
+}
+
+static void
+set_pre_defined_field (GSList **pre_defined_fields)
+{
+ *pre_defined_fields = NULL;
+
+ #define add(x) *pre_defined_fields = g_slist_append (*pre_defined_fields, GINT_TO_POINTER (x))
+
+ add (E_CONTACT_CSV_GIVEN_NAME);
+ add (E_CONTACT_CSV_FAMILY_NAME);
+ add (E_CONTACT_CSV_FULL_NAME);
+ add (E_CONTACT_CSV_NICKNAME);
+ add (E_CONTACT_CSV_EMAIL_1);
+ add (E_CONTACT_CSV_EMAIL_2);
+ add (E_CONTACT_CSV_EMAIL_3);
+ add (E_CONTACT_CSV_EMAIL_4);
+ add (E_CONTACT_CSV_WANTS_HTML);
+ add (E_CONTACT_CSV_PHONE_BUSINESS);
+ add (E_CONTACT_CSV_PHONE_HOME);
+ add (E_CONTACT_CSV_PHONE_BUSINESS_FAX);
+ add (E_CONTACT_CSV_PHONE_PAGER);
+ add (E_CONTACT_CSV_PHONE_MOBILE);
+ add (E_CONTACT_CSV_ADDRESS_HOME_STREET);
+ add (E_CONTACT_CSV_ADDRESS_HOME_EXT);
+ add (E_CONTACT_CSV_ADDRESS_HOME_CITY);
+ add (E_CONTACT_CSV_ADDRESS_HOME_REGION);
+ add (E_CONTACT_CSV_ADDRESS_HOME_POSTCODE);
+ add (E_CONTACT_CSV_ADDRESS_HOME_COUNTRY);
+ add (E_CONTACT_CSV_ADDRESS_BUSINESS_STREET);
+ add (E_CONTACT_CSV_ADDRESS_BUSINESS_EXT);
+ add (E_CONTACT_CSV_ADDRESS_BUSINESS_CITY);
+ add (E_CONTACT_CSV_ADDRESS_BUSINESS_REGION);
+ add (E_CONTACT_CSV_ADDRESS_BUSINESS_POSTCODE);
+ add (E_CONTACT_CSV_ADDRESS_BUSINESS_COUNTRY);
+ add (E_CONTACT_CSV_TITLE);
+ add (E_CONTACT_CSV_OFFICE);
+ add (E_CONTACT_CSV_ORG);
+ add (E_CONTACT_CSV_HOMEPAGE_URL);
+ add (E_CONTACT_CSV_CALENDAR_URI);
+ add (E_CONTACT_CSV_BIRTH_DATE_YEAR);
+ add (E_CONTACT_CSV_BIRTH_DATE_MONTH);
+ add (E_CONTACT_CSV_BIRTH_DATE_DAY);
+ add (E_CONTACT_CSV_NOTE);
+
+ #undef add
+}
+
+static gint
+output_n_cards_file (FILE *outputfile,
+ GSList *contacts,
+ gint size,
+ gint begin_no,
+ CARD_FORMAT format)
+{
+ gint i;
+ if (format == CARD_FORMAT_VCARD) {
+ for (i = begin_no; i < size + begin_no; i++) {
+ EContact *contact = g_slist_nth_data (contacts, i);
+ gchar *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+ fprintf (outputfile, "%s\n", vcard);
+ g_free (vcard);
+ }
+ } else if (format == CARD_FORMAT_CSV) {
+ gchar *csv_fields_name;
+
+ if (!pre_defined_fields)
+ set_pre_defined_field (&pre_defined_fields);
+
+ csv_fields_name = e_contact_csv_get_header_line (pre_defined_fields);
+ fprintf (outputfile, "%s\n", csv_fields_name);
+ g_free (csv_fields_name);
+
+ for (i = begin_no; i < size + begin_no; i++) {
+ EContact *contact = g_slist_nth_data (contacts, i);
+ gchar *csv = e_contact_get_csv (contact, pre_defined_fields);
+ fprintf (outputfile, "%s\n", csv);
+ g_free (csv);
+ }
+ }
+
+ return SUCCESS;
+
+}
+
+static void
+action_list_cards (GSList *contacts,
+ ActionContext *p_actctx)
+{
+ FILE *outputfile;
+ long length;
+ CARD_FORMAT format;
+
+ length = g_slist_length (contacts);
+
+ if (length <= 0) {
+ g_warning ("Couldn't load addressbook correctly!!!! %s####", p_actctx->addressbook_source_uid
?
+ p_actctx->addressbook_source_uid : "NULL");
+ exit (-1);
+ }
+
+ if (p_actctx->output_file == NULL) {
+ outputfile = stdout;
+ } else {
+ /* fopen output file */
+ if (!(outputfile = g_fopen (p_actctx->output_file, "w"))) {
+ g_warning (_("Can not open file"));
+ exit (-1);
+ }
+ }
+
+ if (p_actctx->IsVCard == TRUE)
+ format = CARD_FORMAT_VCARD;
+ else
+ format = CARD_FORMAT_CSV;
+
+ output_n_cards_file (outputfile, contacts, length, 0, format);
+
+ if (p_actctx->output_file != NULL) {
+ fclose (outputfile);
+ }
+}
+
+static void
+action_list_cards_init (ActionContext *p_actctx)
+{
+ ESourceRegistry *registry;
+ EClient *client;
+ EBookClient *book_client;
+ EBookQuery *query;
+ ESource *source;
+ GSList *contacts;
+ const gchar *uid;
+ gchar *query_str;
+ GError *error = NULL;
+
+ registry = p_actctx->registry;
+ uid = p_actctx->addressbook_source_uid;
+
+ if (uid != NULL)
+ source = e_source_registry_ref_source (registry, uid);
+ else
+ source = e_source_registry_ref_default_address_book (registry);
+
+ if (!source) {
+ g_warning (
+ "Couldn't load addressbook %s: Addressbook doesn't exist",
+ p_actctx->addressbook_source_uid ?
+ p_actctx->addressbook_source_uid :
+ "'default'");
+ exit (-1);
+ }
+
+ client = e_book_client_connect_sync (source, 30, NULL, &error);
+
+ g_object_unref (source);
+
+ /* Sanity check. */
+ g_return_if_fail (
+ ((client != NULL) && (error == NULL)) ||
+ ((client == NULL) && (error != NULL)));
+
+ if (error != NULL) {
+ g_warning (
+ "Couldn't load addressbook %s: %s",
+ p_actctx->addressbook_source_uid ?
+ p_actctx->addressbook_source_uid :
+ "'default'", error->message);
+ g_error_free (error);
+ exit (-1);
+ }
+
+ book_client = E_BOOK_CLIENT (client);
+
+ query = e_book_query_any_field_contains ("");
+ query_str = e_book_query_to_string (query);
+ e_book_query_unref (query);
+
+ e_book_client_get_contacts_sync (
+ book_client, query_str, &contacts, NULL, &error);
+
+ action_list_cards (contacts, p_actctx);
+
+ g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+ g_slist_free (contacts);
+ g_object_unref (book_client);
+
+ if (error != NULL) {
+ g_warning ("Failed to get contacts: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static gboolean
+call_main_loop_quit_idle_cb (gpointer user_data)
+{
+ g_main_loop_quit (user_data);
+
+ return FALSE;
+}
+
+static gpointer
+addressbook_export_thread (gpointer user_data)
+{
+ ActionContext *actctx = user_data;
+
+ g_return_val_if_fail (actctx != NULL, NULL);
+
+ /* do actions */
+ if (actctx->action_type == ACTION_LIST_FOLDERS) {
+ action_list_folders_init (actctx);
+
+ } else if (actctx->action_type == ACTION_LIST_CARDS) {
+ action_list_cards_init (actctx);
+
+ } else {
+ g_warning (_("Unhandled error"));
+ exit (-1);
+ }
+
+ g_idle_add (call_main_loop_quit_idle_cb, actctx->main_loop);
+
+ return NULL;
+}
+
+static gboolean
+addressbook_export_start_idle (gpointer user_data)
+{
+ ActionContext *actctx = user_data;
+ GThread *thread;
+
+ g_return_val_if_fail (actctx != NULL, FALSE);
+
+ thread = g_thread_new (NULL, addressbook_export_thread, actctx);
+ g_thread_unref (thread);
+
+ return FALSE;
+}
+
+/* Command-Line Options */
+static gchar *opt_output_file = NULL;
+static gboolean opt_list_folders_mode = FALSE;
+static gchar *opt_output_format = NULL;
+static gchar *opt_addressbook_source_uid = NULL;
+static gchar **opt_remaining = NULL;
+
+static GOptionEntry entries[] = {
+ { "output", '\0', 0,
+ G_OPTION_ARG_STRING, &opt_output_file,
+ N_("Specify the output file instead of standard output"),
+ N_("OUTPUTFILE") },
+ { "list-addressbook-folders", 'l', 0,
+ G_OPTION_ARG_NONE, &opt_list_folders_mode,
+ N_("List local address book folders") },
+ { "format", '\0', 0,
+ G_OPTION_ARG_STRING, &opt_output_format,
+ N_("Show cards as vcard or csv file"),
+ N_("[vcard|csv]") },
+ { G_OPTION_REMAINING, '\0', 0,
+ G_OPTION_ARG_STRING_ARRAY, &opt_remaining },
+ { NULL }
+};
+
+gint
+main (gint argc,
+ gchar **argv)
+{
+ ActionContext actctx;
+ GOptionContext *context;
+ GError *error = NULL;
+ gint IsCSV = FALSE;
+ gint IsVCard = FALSE;
+
+#ifdef G_OS_WIN32
+ e_util_win32_initialize ();
+#endif
+
+ /*i18n-lize */
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ context = g_option_context_new (NULL);
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ exit (-1);
+ }
+
+ actctx.action_type = ACTION_NOTHING;
+ actctx.registry = e_source_registry_new_sync (NULL, &error);
+ if (error != NULL) {
+ g_printerr ("%s\n", error->message);
+ g_error_free (error);
+ exit (-1);
+ }
+
+ /* Parsing Parameter */
+ if (opt_remaining && g_strv_length (opt_remaining) > 0)
+ opt_addressbook_source_uid = g_strdup (opt_remaining[0]);
+
+ if (opt_list_folders_mode) {
+ actctx.action_type = ACTION_LIST_FOLDERS;
+ if (opt_addressbook_source_uid != NULL || opt_output_format != NULL) {
+ g_warning (_("Command line arguments error, please use --help option to see the
usage."));
+ exit (-1);
+ }
+ } else {
+
+ actctx.action_type = ACTION_LIST_CARDS;
+
+ /* check the output format */
+ if (opt_output_format == NULL) {
+ IsVCard = TRUE;
+ } else {
+ IsCSV = !strcmp (opt_output_format, "csv");
+ IsVCard = !strcmp (opt_output_format, "vcard");
+ if (IsCSV == FALSE && IsVCard == FALSE) {
+ g_warning (_("Only support csv or vcard format."));
+ exit (-1);
+ }
+ }
+ }
+
+ actctx.output_file = opt_output_file;
+ actctx.IsCSV = IsCSV;
+ actctx.IsVCard = IsVCard;
+ actctx.addressbook_source_uid = opt_addressbook_source_uid;
+
+ g_idle_add (addressbook_export_start_idle, &actctx);
+
+ actctx.main_loop = g_main_loop_new (NULL, FALSE);
+
+ g_main_loop_run (actctx.main_loop);
+
+ g_object_unref (actctx.registry);
+ g_main_loop_unref (actctx.main_loop);
+
+ return 0;
+}
diff --git a/tools/addressbook-export/csv2vcard.in b/tools/addressbook-export/csv2vcard.in
new file mode 100755
index 0000000..144d30b
--- /dev/null
+++ b/tools/addressbook-export/csv2vcard.in
@@ -0,0 +1,234 @@
+#! PERL@ -w
+#
+# cvs2vcard - Script to convert Outlook CSV files into vCard files
+# suitable to be imported into Evolution.
+#
+# Copyright (C) 2001 Ximian, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License 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 Lesser General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# Author: Michael MacDonald <mjmac ximian com>
+#
+
+use strict;
+use diagnostics;
+use Text::ParseWords;
+
+sub usage
+{
+ print STDERR << "--EndOfUsage";
+
+Takes a CSV-formatted list of contacts from Outlook and attempts to
+convert it into a list of vCards suitable for import into Evolution.
+
+Usage: $0 [infile outfile]
+
+--EndOfUsage
+
+ exit;
+}
+
+sub is_recognized_format
+{
+ my $line = shift;
+
+ # Making some assumptions here... Prolly OK.
+ return $line =~ /(First Name|Middle Name|Last Name)/;
+}
+
+sub map_columns
+{
+ my $line = shift;
+
+ my @names = parse_line(',', 0, $line);
+
+ my $ctr = 0;
+ my %fieldmap = map { $_ => $ctr++ } @names;
+
+ return %fieldmap;
+}
+
+sub build_vcard_attr_from_def
+{
+ my ($def, $fields, $map) = @_;
+
+ # Valid chars for lookup (from Outlook CSV) are
+ # A-Za-z0-9_-'/
+ # Valid chars for formatting of attr are
+ # \s,|
+ my @lookup = map { s/=0A$//; s/[^\w\s\-'\/]//; $_; } split /[\s,]*\|[\s,]*/, $def;
+
+ foreach my $el (@lookup) {
+ unless (defined($map->{ $el })) {
+ print STDERR "$el is undefined\n";
+ next;
+ }
+ if (defined($fields->[$map->{ $el }])) {
+ unless ($fields->[$map->{ $el }] =~ /(^$|0\/0\/00)/) {
+ $def =~ s/$el/$fields->[$map->{ $el }]/;
+ } else {
+ $def =~ s/((?<=\|)\s*)?$el(\s*?(?=\|))?(=0A)?,?//;
+ }
+ } else {
+ $def =~ s/((?<=\|)\s*)?$el(\s*?(?=\|))?(=0A)?,?//;
+ }
+ }
+ # Get rid of field delimiters
+ $def =~ s/\|//g;
+ # Snip off any trailing semicolons or whitespace
+ $def =~ s/[\s;]*$//;
+
+ return $def;
+}
+
+sub build_vcard_from_line {
+ my ($line, %map) = @_;
+ my %vcard;
+
+ my @fields = parse_line(',', 0, $line);
+
+ my %vcard_def = ( FN => 'Title |First Name |Middle Name |Last Name |Suffix',
+ N => 'Last Name| Suffix|;First Name|;Middle Name|;Title',
+ 'ADR;WORK' => 'PO Box|;Business Street 2|;Business Street|;Business City|;Business
State|;Business Postal Code|;Business Country',
+ 'LABEL;QUOTED-PRINTABLE;WORK' => 'PO Box |Business Street=0A|Business Street 2=0A|Business
City,| Business State| Business Postal Code=0A|Business Country',
+ 'TEL;WORK;VOICE' => 'Business Phone',
+ 'TEL;WORK;VOICE2' => 'Business Phone 2',
+ 'TEL;WORK;FAX' => 'Business Fax',
+ 'TEL;WORK;COMPANY' => 'Company Main Phone',
+ 'ADR;HOME' => ';Home Street 2|;Home Street|;Home City|;Home State|;Home Postal Code|;Home
Country',
+ 'LABEL;QUOTED-PRINTABLE;HOME' => 'Home Street=0A|Home Street 2=0A|Home City,| Home State|
Home Postal Code=0A|Home Country',
+ 'TEL;HOME;VOICE' => 'Home Phone',
+ 'TEL;HOME;VOICE2' => 'Home Phone 2',
+ 'TEL;HOME;FAX' => 'Home Fax',
+ 'ADR;POSTAL' => ';Other Street 2|;Other Street|;Other City|;Other State|;Other Postal
Code|;Other Country',
+ 'LABEL;QUOTED-PRINTABLE;POSTAL' => 'Other Street=0A|Other Street 2=0A|Other City,| Other
State| Other Postal Code=0A|Other Country',
+ 'TEL;VOICE' => 'Other Phone',
+ 'TEL;FAX' => 'Other Fax',
+ 'TEL;CELL' => 'Mobile Phone',
+ 'TEL;CAR' => 'Car Phone',
+ 'TEL;PAGER' => 'Pager',
+ 'TEL;PREF' => 'Primary Phone',
+ 'TEL;ISDN' => 'ISDN',
+ 'TEL;X-EVOLUTION-CALLBACK' => 'Callback',
+ 'TEL;X-EVOLUTION-TTYTDD' => 'TTY/TDD Phone',
+ 'TEL;X-EVOLUTION-TELEX' => 'Telex',
+ 'TEL;X-EVOLUTION-RADIO' => 'Radio Phone',
+ 'EMAIL;INTERNET' => 'E-mail Address',
+ 'EMAIL;INTERNET2' => 'E-mail 2 Address',
+ 'EMAIL;INTERNET3' => 'E-mail 3 Address',
+ ORG => 'Company|;Department',
+ TITLE => 'Job Title',
+ ROLE => 'Profession',
+ 'X-EVOLUTION-ASSISTANT' => "Assistant's Name",
+ 'TEL;X-EVOLUTION-ASSISTANT' => "Assistant's Phone",
+ 'X-EVOLUTION-SPOUSE' => 'Spouse',
+ 'X-EVOLUTION-ANNIVERSARY' => 'Anniversary',
+ 'X-EVOLUTION-MANAGER' => "Manager's Name",
+ 'X-EVOLUTION-OFFICE' => 'Office Location',
+ BDAY => 'Birthday',
+ NOTE => 'Notes',
+ FBURL => 'Internet Free Busy',
+ URL => 'Web Page',
+ );
+
+ foreach my $key (keys(%vcard_def)) {
+ my $attr = build_vcard_attr_from_def($vcard_def{ $key }, \ fields, \%map);
+ if (defined($attr)) {
+ $vcard{ $key } = $attr unless ($attr =~ /^$/);
+ }
+ }
+
+ return %vcard;
+}
+
+sub print_vcard_to_fh
+{
+ my ($fh, %vcard) = @_;
+
+ print $fh "BEGIN:VCARD\n";
+ foreach my $key (keys(%vcard)) {
+ # Dirty hack because Evolution's vcard stores multiple email addrs
+ # with same sttribute, hence key collision. Bleah.
+ # Ugh! Same deal for multiple phones... (eg. bus. phone)
+ #
+ # And finally, while we're special-casing... Outlook exports dates
+ # differently, so munge 'em if we find 'em.
+ if ($key =~ /EMAIL;INTERNET/o) {
+ (my $temp = $key) =~ s/\d$//;
+ print $fh "$temp:$vcard{ $key }\n";
+ } elsif ($key =~ /TEL;(HOME|WORK)/o) {
+ (my $temp = $key) =~ s/\d$//;
+ print $fh "$temp:$vcard{ $key }\n";
+ } elsif ($key =~ /(BDAY|X\-EVOLUTION\-ANNIVERSARY)/o) {
+ my $temp = $vcard{ $key };
+ if ($temp =~ /(\d\d)\/(\d\d)\/(\d\d)/) {
+ # Y2k !! MS Didn't learn anything.
+ # Hope no one was born before 1915
+ if ((1900 + $3) < 1915) {
+ print $fh "$key:20$3-$1-$2\n";
+ } else {
+ print $fh "$key:19$3-$1-$2\n";
+ }
+ } else {
+ # Something's funky... Just delete the attribute
+ print STDERR "Couldn't figure out what to do with $key:$vcard{ $key }\n";
+ delete($vcard{ $key });
+ }
+ } else {
+ print $fh "$key:$vcard{ $key }\n";
+ }
+ }
+ print $fh "END:VCARD\n\n";
+}
+
+my $in = $ARGV[0];
+my $out = $ARGV[1];
+
+usage() unless(defined($in) && defined($out));
+
+open (IN, $in)
+ or die "Can't open($in): $!\n";
+
+open (OUT, ">$out")
+ or die "Can't open($out): $!\n";
+
+my $linectr = 0;
+my %map;
+
+while (my $line = <IN>) {
+ $line =~ s/\r//g;
+ $line =~ s/\n$//;
+ if ($linectr == 0) {
+ $linectr++;
+ usage() unless is_recognized_format($line);
+ %map = map_columns($line);
+ #if ($line =~ /\r\n$/) {
+ # print STDERR "Apparenlty found DOS-style EOL indicators...\n";
+ $/ = "\r\n";
+ #}
+ } else {
+ $linectr++;
+ while ($line =~ /^(("([^"]|\n|"")*")?,)*"([^"]|\n|"")*$/) {
+ my $temp = $line;
+ $line = <IN>;
+ $line =~ s/\r//g;
+ $line =~ s/\n$//;
+ $line = "$temp $line";
+ }
+ my %vcard = build_vcard_from_line($line, %map);
+ print_vcard_to_fh(\*OUT, %vcard);
+ }
+}
+
+close(IN);
+close(OUT);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]