[evolution-data-server] Bug 443716 - Move evolution-addressbook-export to e-d-s



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]