diff options
-rw-r--r-- | addressbook/ChangeLog | 14 | ||||
-rw-r--r-- | addressbook/importers/.cvsignore | 8 | ||||
-rw-r--r-- | addressbook/importers/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in | 29 | ||||
-rw-r--r-- | addressbook/importers/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in | 29 | ||||
-rw-r--r-- | addressbook/importers/Makefile.am | 53 | ||||
-rw-r--r-- | addressbook/importers/evolution-ldif-importer.c | 610 | ||||
-rw-r--r-- | addressbook/importers/evolution-vcard-importer.c | 269 |
7 files changed, 1012 insertions, 0 deletions
diff --git a/addressbook/ChangeLog b/addressbook/ChangeLog index a39064a403..400de05d1f 100644 --- a/addressbook/ChangeLog +++ b/addressbook/ChangeLog @@ -1,3 +1,17 @@ +2004-02-06 JP Rosevear <jpr@ximian.com> + + * importers/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in: + shlib importer info + + * importers/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in: + ditto + + * importers/Makefile.am: build shlib addressbook importers + + * importers/evolution-ldif-importer.c: First crack at resurrecting + + * importers/evolution-vcard-importer.c: ditto + 2004-02-03 Chris Toshok <toshok@ximian.com> * gui/widgets/eab-contact-display.c (on_url_requested): remove diff --git a/addressbook/importers/.cvsignore b/addressbook/importers/.cvsignore new file mode 100644 index 0000000000..665a07cc24 --- /dev/null +++ b/addressbook/importers/.cvsignore @@ -0,0 +1,8 @@ +.deps +.libs +Makefile +Makefile.in +*.lo +*.la +GNOME_Evolution_Addressbook*.server +GNOME_Evolution_Addressbook*.server.in diff --git a/addressbook/importers/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in b/addressbook/importers/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in new file mode 100644 index 0000000000..f397674fd3 --- /dev/null +++ b/addressbook/importers/GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in @@ -0,0 +1,29 @@ +<oaf_info> + +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_LDIF_ImporterFactory" + type="shlib" + location="@IMPORTERSDIR@/libevolution-addressbook-ldif-importer.so"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/ObjectFactory:1.0"/> + </oaf_attribute> + + <oaf_attribute name="name" type="string" + _value="Evolution LDIF importer"/> +</oaf_server> + +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_LDIF_Importer" + type="factory" + location="OAFIID:GNOME_Evolution_Addressbook_LDIF_ImporterFactory"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/Evolution/Importer:@VERSION@"/> + </oaf_attribute> + + <oaf_attribute name="evolution:menu_name" type="string" + _value="LDAP Data Interchange Format (.ldif)"/> + <oaf_attribute name="name" type="string" + _value="Evolution LDIF importer"/> +</oaf_server> + +</oaf_info> diff --git a/addressbook/importers/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in b/addressbook/importers/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in new file mode 100644 index 0000000000..1d434fbab9 --- /dev/null +++ b/addressbook/importers/GNOME_Evolution_Addressbook_VCard_Importer.server.in.in @@ -0,0 +1,29 @@ +<oaf_info> + +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_VCard_ImporterFactory" + type="shlib" + location="@IMPORTERSDIR@/libevolution-addressbook-vcard-importer.so"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/ObjectFactory:1.0"/> + </oaf_attribute> + + <oaf_attribute name="name" type="string" + _value="Evolution VCard importer"/> +</oaf_server> + +<oaf_server iid="OAFIID:GNOME_Evolution_Addressbook_VCard_Importer" + type="factory" + location="OAFIID:GNOME_Evolution_Addressbook_VCard_ImporterFactory"> + + <oaf_attribute name="repo_ids" type="stringv"> + <item value="IDL:GNOME/Evolution/Importer:@VERSION@"/> + </oaf_attribute> + + <oaf_attribute name="evolution:menu_name" type="string" + _value="VCard (.vcf, .gcrd)"/> + <oaf_attribute name="name" type="string" + _value="Evolution VCard Importer"/> +</oaf_server> + +</oaf_info> diff --git a/addressbook/importers/Makefile.am b/addressbook/importers/Makefile.am new file mode 100644 index 0000000000..3c04c22f37 --- /dev/null +++ b/addressbook/importers/Makefile.am @@ -0,0 +1,53 @@ +importersdir = $(privlibdir)/evolution-addressbook-importers + +importers_LTLIBRARIES = \ + libevolution-addressbook-ldif-importer.la \ + libevolution-addressbook-vcard-importer.la + +INCLUDES = \ + -DEVOLUTION_LOCALEDIR=\""$(localedir)"\" \ + -DEVOLUTION_SOUNDDIR=\""$(soundsdir)"\" \ + -DG_LOG_DOMAIN=\"Evolution-Importer\" \ + -I$(top_srcdir) \ + -I$(top_builddir)/shell \ + -I$(top_srcdir)/shell \ + -I$(top_srcdir)/addressbook \ + -I$(top_builddir)/addressbook \ + $(EVOLUTION_ADDRESSBOOK_CFLAGS) + +# VCard Importer +libevolution_addressbook_vcard_importer_la_SOURCES = \ + evolution-vcard-importer.c + +libevolution_addressbook_vcard_importer_la_LDFLAGS = -avoid-version -module + +libevolution_addressbook_vcard_importer_la_LIBADD = \ + $(top_builddir)/shell/importer/libevolution-importer.la \ + $(top_builddir)/e-util/libeutil.la \ + $(IMPORTERS_LIBS) + +# LDIF Importer +libevolution_addressbook_ldif_importer_la_SOURCES = \ + evolution-ldif-importer.c + +libevolution_addressbook_ldif_importer_la_LDFLAGS = -avoid-version -module + +libevolution_addressbook_ldif_importer_la_LIBADD = \ + $(top_builddir)/shell/importer/libevolution-importer.la \ + $(top_builddir)/e-util/libeutil.la \ + $(IMPORTERS_LIBS) + +server_in_files = \ + GNOME_Evolution_Addressbook_LDIF_Importer.server.in.in \ + GNOME_Evolution_Addressbook_VCard_Importer.server.in.in +server_DATA = $(server_in_files:.server.in.in=_$(BASE_VERSION).server) +@EVO_SERVER_RULE@ +@INTLTOOL_SERVER_RULE@ + +BUILT_SOURCES = $(server_DATA) +CLEANFILES = $(BUILT_SOURCES) + +EXTRA_DIST = $(server_in_files) + +dist-hook: + cd $(distdir); rm -f $(BUILT_SOURCES) diff --git a/addressbook/importers/evolution-ldif-importer.c b/addressbook/importers/evolution-ldif-importer.c new file mode 100644 index 0000000000..eef9f22d23 --- /dev/null +++ b/addressbook/importers/evolution-ldif-importer.c @@ -0,0 +1,610 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * LDIF importer. LDIF is the file format of an exported Netscape + * addressbook. + * + * Framework copied from evolution-gnomecard-importer.c + * + * Michael M. Morrison (mmorrison@kqcorp.com) + * + * Multi-line value support, mailing list support, base64 support, and + * various fixups: Chris Toshok (toshok@ximian.com) + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <ctype.h> +#include <string.h> + +#include <gtk/gtkwidget.h> +#include <gtk/gtkvbox.h> +#include <libgnome/gnome-init.h> +#include <bonobo/bonobo-shlib-factory.h> +#include <bonobo/bonobo-main.h> +#include <bonobo/bonobo-control.h> + +#include <libebook/e-book.h> + +#include <importer/evolution-importer.h> +#include <importer/GNOME_Evolution_Importer.h> +#include <widgets/misc/e-source-selector.h> +#include <util/eab-destination.h> + +#define COMPONENT_FACTORY_IID "OAFIID:GNOME_Evolution_Addressbook_LDIF_ImporterFactory" +#define COMPONENT_IID "OAFIID:GNOME_Evolution_Addressbook_LDIF_Importer" + +static GHashTable *dn_contact_hash; + +typedef struct { + ESource *primary; + + GList *contactlist; + GList *iterator; + EBook *book; + gboolean ready; +} LDIFImporter; + +static struct { + char *ldif_attribute; + EContactField contact_field; +#define FLAG_ADDRESS 0x01 + int flags; +} +ldif_fields[] = { + { "cn", E_CONTACT_FULL_NAME }, + { "mail", E_CONTACT_EMAIL }, +#if 0 + { "givenname", E_CONTACT_GIVEN_NAME }, +#endif + { "sn", E_CONTACT_FAMILY_NAME }, + { "xmozillanickname", E_CONTACT_NICKNAME }, + { "o", E_CONTACT_ORG }, + { "locality", 0, FLAG_ADDRESS}, + { "st", 0, FLAG_ADDRESS }, + { "streetaddress", 0, FLAG_ADDRESS }, + { "title", E_CONTACT_TITLE }, + { "postalcode", 0, FLAG_ADDRESS }, + { "countryname", 0, FLAG_ADDRESS }, + { "telephonenumber", E_CONTACT_PHONE_BUSINESS}, + { "homephone", E_CONTACT_PHONE_HOME }, + { "facsimiletelephonenumber", E_CONTACT_PHONE_BUSINESS_FAX }, + { "ou", E_CONTACT_ORG_UNIT }, + { "pagerphone", E_CONTACT_PHONE_PAGER }, + { "cellphone", E_CONTACT_PHONE_MOBILE }, + { "homeurl", E_CONTACT_HOMEPAGE_URL }, + { "description", E_CONTACT_NOTE }, + { "xmozillausehtmlmail", E_CONTACT_WANTS_HTML } +}; +static int num_ldif_fields = sizeof(ldif_fields) / sizeof (ldif_fields[0]); + +static unsigned char base64_rank[256] = { + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +}; + +/** + * base64_decode_step: decode a chunk of base64 encoded data + * @in: input stream + * @len: max length of data to decode + * @out: output stream + * @state: holds the number of bits that are stored in @save + * @save: leftover bits that have not yet been decoded + * + * Decodes a chunk of base64 encoded data + **/ +static int +base64_decode_step(unsigned char *in, int len, unsigned char *out, int *state, unsigned int *save) +{ + register unsigned char *inptr, *outptr; + unsigned char *inend, c; + register unsigned int v; + int i; + + inend = in+len; + outptr = out; + + /* convert 4 base64 bytes to 3 normal bytes */ + v=*save; + i=*state; + inptr = in; + while (inptr<inend) { + c = base64_rank[*inptr++]; + if (c != 0xff) { + v = (v<<6) | c; + i++; + if (i==4) { + *outptr++ = v>>16; + *outptr++ = v>>8; + *outptr++ = v; + i=0; + } + } + } + + *save = v; + *state = i; + + /* quick scan back for '=' on the end somewhere */ + /* fortunately we can drop 1 output char for each trailing = (upto 2) */ + i=2; + while (inptr>in && i) { + inptr--; + if (base64_rank[*inptr] != 0xff) { + if (*inptr == '=') + outptr--; + i--; + } + } + + /* if i!= 0 then there is a truncation error! */ + return outptr-out; +} + +static int +base64_decode_simple (char *data, int len) +{ + int state = 0; + unsigned int save = 0; + + return base64_decode_step ((unsigned char *)data, len, + (unsigned char *)data, &state, &save); +} + +static GString * +getValue( char **src ) +{ + GString *dest = g_string_new(""); + char *s = *src; + gboolean need_base64 = (*s == ':'); + + copy_line: + while( *s != 0 && *s != '\n' && *s != '\r' ) + dest = g_string_append_c (dest, *s++); + + if (*s == '\r') s++; + if (*s == '\n') s++; + + /* check for continuation here */ + if (*s == ' ') { + s++; + goto copy_line; + } + + if (need_base64) { + int new_len; + /* it's base64 encoded */ + dest = g_string_erase (dest, 0, 2); + new_len = base64_decode_simple (dest->str, strlen (dest->str)); + dest = g_string_truncate (dest, new_len); + } + + *src = s; + + return dest; +} + +static gboolean +parseLine (EContact *contact, EContactAddress *address, char **buf) +{ + char *ptr; + char *colon, *value; + gboolean field_handled; + GString *ldif_value; + + ptr = *buf; + + /* if the string is empty, return */ + if (*ptr == '\0') { + *buf = NULL; + return TRUE; + } + + /* skip comment lines */ + if (*ptr == '#') { + ptr = strchr (ptr, '\n'); + if (!ptr) + *buf = NULL; + else + *buf = ptr + 1; + return TRUE; + } + + /* first, check for a 'continuation' line */ + if( ptr[0] == ' ' && ptr[1] != '\n' ) { + g_warning ("unexpected continuation line"); + return FALSE; + } + + colon = (char *)strchr( ptr, ':' ); + if (colon) { + int i; + + *colon = 0; + value = colon + 1; + while ( isspace(*value) ) + value++; + + ldif_value = getValue(&value ); + + field_handled = FALSE; + for (i = 0; i < num_ldif_fields; i ++) { + if (!g_ascii_strcasecmp (ptr, ldif_fields[i].ldif_attribute)) { + if (ldif_fields[i].flags & FLAG_ADDRESS) { + if (!g_ascii_strcasecmp (ptr, "locality")) + address->locality = g_strdup (ldif_value->str); + else if (!g_ascii_strcasecmp (ptr, "countryname")) + address->country = g_strdup (ldif_value->str); + else if (!g_ascii_strcasecmp (ptr, "postalcode")) + address->code = g_strdup (ldif_value->str); + else if (!g_ascii_strcasecmp (ptr, "st")) + address->region = g_strdup (ldif_value->str); + else if (!g_ascii_strcasecmp (ptr, "streetaddress")) + address->street = g_strdup (ldif_value->str); + } + else { + /* FIXME is everything a string? */ + e_contact_set (contact, ldif_fields[i].contact_field, ldif_value->str); + g_message ("set %s to %s", ptr, ldif_value->str); + } + field_handled = TRUE; + break; + } + } + + /* handle objectclass/dn/member out here */ + if (!field_handled) { + if (!g_ascii_strcasecmp (ptr, "dn")) + g_hash_table_insert (dn_contact_hash, g_strdup(ldif_value->str), contact); + else if (!g_ascii_strcasecmp (ptr, "objectclass") && !g_ascii_strcasecmp (ldif_value->str, "groupofnames")) { + e_contact_set (contact, E_CONTACT_IS_LIST, GINT_TO_POINTER (TRUE)); + } + else if (!g_ascii_strcasecmp (ptr, "member")) { + GList *email; + + email = e_contact_get (contact, E_CONTACT_EMAIL); + email = g_list_append (email, g_strdup (ldif_value->str)); + e_contact_set (contact, E_CONTACT_EMAIL, email); + + g_list_foreach (email, (GFunc) g_free, NULL); + g_list_free (email); + } + } + + /* put the colon back the way it was, just for kicks */ + *colon = ':'; + + g_string_free (ldif_value, TRUE); + } + else { + g_warning ("unrecognized entry %s", ptr); + return FALSE; + } + + *buf = value; + + return TRUE; +} + +static EContact * +getNextLDIFEntry( FILE *f ) +{ + EContact *contact; + EContactAddress *address; + GString *str; + char line[1024]; + char *buf; + + str = g_string_new (""); + /* read from the file until we get to a blank line (or eof) */ + while (!feof (f)) { + if (!fgets (line, sizeof(line), f)) + break; + if (line[0] == '\n' || (line[0] == '\r' && line[1] == '\n')) + break; + str = g_string_append (str, line); + } + + if (strlen (str->str) == 0) { + g_string_free (str, TRUE); + return NULL; + } + + /* now parse that entry */ + contact = e_contact_new (); + /* FIXME Should ebook have a utility routine for this? */ + address = g_new0 (EContactAddress, 1); + + buf = str->str; + while (buf) { + if (!parseLine (contact, address, &buf)) { + /* parsing error */ + g_object_unref (contact); + return NULL; + } + } + + /* fill in the address */ + /* FIXME Do we want to hard code the address type? */ + e_contact_set (contact, E_CONTACT_ADDRESS_HOME, address); + + g_string_free (str, TRUE); + + return contact; +} + +static void +resolve_list_card (LDIFImporter *gci, EContact *contact) +{ + GList *email, *l; + char *full_name; + + /* set file_as to full_name so we don't later try and figure + out a first/last name for the list. */ + full_name = e_contact_get (contact, E_CONTACT_FULL_NAME); + if (full_name) + e_contact_set (contact, E_CONTACT_FILE_AS, full_name); + g_free (full_name); + + /* FIMXE getting might not be implemented in ebook */ + email = e_contact_get (contact, E_CONTACT_EMAIL); + for (l = email; l; l = l->next) { + /* FIXME How did the dn get into the email list? */ + const char *dn = l->data; + EContact *dn_contact = g_hash_table_lookup (dn_contact_hash, dn); + + /* break list chains here, since we don't support them just yet */ + if (dn_contact && !e_contact_get (dn_contact, E_CONTACT_IS_LIST)) { + EABDestination *dest; + gchar *dest_xml; + + /* Hard-wired for default e-mail, since netscape only exports 1 email address */ + dest = eab_destination_new (); + eab_destination_set_contact (dest, dn_contact, 0); + dest_xml = eab_destination_export (dest); + g_object_unref (dest); + + if (dest_xml) { + g_free (dn); + l->data = dest_xml; + } + else { + /* FIXME Delete from the list properly */ + g_free (dn); + l->data = NULL; + } + } + else { + /* FIXME Delete from the list properly */ + g_free (dn); + l->data = NULL; + } + } + e_contact_set (contact, E_CONTACT_EMAIL, email); + + g_list_foreach (email, (GFunc) g_free, NULL); + g_list_free (email); +} + +static GList * +create_contacts_from_ldif (const char *filename) +{ + GList * list = NULL; + GList * list_list = NULL; + FILE * file; + EContact *contact; + + if(!( file = fopen( filename, "r" ) )) { + g_warning("Can't open .ldif file"); + return NULL; + } + + dn_contact_hash = g_hash_table_new (g_str_hash, g_str_equal); + + while ((contact = getNextLDIFEntry (file))) { + + if (e_contact_get (contact, E_CONTACT_IS_LIST)) + list_list = g_list_append (list_list, contact); + else + list = g_list_append (list, contact); + } + + fclose (file); + + list = g_list_reverse (list); + list_list = g_list_reverse (list_list); + list = g_list_concat (list, list_list); + + return list; +} + +/* EvolutionImporter methods */ +static void +process_item_fn (EvolutionImporter *importer, + CORBA_Object listener, + void *closure, + CORBA_Environment *ev) +{ + LDIFImporter *gci = (LDIFImporter *) closure; + EContact *contact; + + if (gci->iterator == NULL) + gci->iterator = gci->contactlist; + + if (gci->ready == FALSE) { + GNOME_Evolution_ImporterListener_notifyResult (listener, + GNOME_Evolution_ImporterListener_NOT_READY, + gci->iterator ? TRUE : FALSE, + ev); + return; + } + + if (gci->iterator == NULL) { + GNOME_Evolution_ImporterListener_notifyResult (listener, + GNOME_Evolution_ImporterListener_UNSUPPORTED_OPERATION, + FALSE, ev); + return; + } + + contact = gci->iterator->data; + /* FIXME I think this could cause 64 bit platform errors */ + if (e_contact_get (contact, E_CONTACT_IS_LIST)) + resolve_list_card (gci, contact); + /* FIXME Error checking */ + e_book_add_contact (gci->book, contact, NULL); + + gci->iterator = gci->iterator->next; + + GNOME_Evolution_ImporterListener_notifyResult (listener, + GNOME_Evolution_ImporterListener_OK, + gci->iterator ? TRUE : FALSE, + ev); + if (ev->_major != CORBA_NO_EXCEPTION) { + g_warning ("Error notifying listeners."); + } + + return; +} + +static void +primary_selection_changed_cb (ESourceSelector *selector, gpointer data) +{ + LDIFImporter *gci = data; + + if (gci->primary) + g_object_unref (gci->primary); + gci->primary = g_object_ref (e_source_selector_peek_primary_selection (selector)); +} + +static void +create_control_fn (EvolutionImporter *importer, Bonobo_Control *control, void *closure) +{ + LDIFImporter *gci = closure; + GtkWidget *vbox, *selector; + ESource *primary; + ESourceList *source_list; + + vbox = gtk_vbox_new (FALSE, FALSE); + + /* FIXME Better error handling */ + if (!e_book_get_addressbooks (&source_list, NULL)) + return; + + selector = e_source_selector_new (source_list); + e_source_selector_show_selection (E_SOURCE_SELECTOR (selector), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), selector, FALSE, TRUE, 6); + + /* FIXME What if no sources? */ + primary = e_source_list_peek_source_any (source_list); + e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (selector), primary); + if (!gci->primary) + gci->primary = g_object_ref (primary); + g_object_unref (source_list); + + g_signal_connect (G_OBJECT (selector), "primary_selection_changed", + G_CALLBACK (primary_selection_changed_cb), gci); + + gtk_widget_show_all (vbox); + + *control = BONOBO_OBJREF (bonobo_control_new (vbox)); +} + +static char *supported_extensions[2] = { + ".ldif", NULL +}; + +static gboolean +support_format_fn (EvolutionImporter *importer, + const char *filename, + void *closure) +{ + char *ext; + int i; + + ext = strrchr (filename, '.'); + if (ext == NULL) { + return FALSE; + } + + for (i = 0; supported_extensions[i] != NULL; i++) { + if (strcmp (supported_extensions[i], ext) == 0) + return TRUE; + } + + return FALSE; +} + +static void +importer_destroy_cb (gpointer data, + GObject *where_object_was) +{ + /* FIXME Implement */ +} + +static gboolean +load_file_fn (EvolutionImporter *importer, + const char *filename, + void *closure) +{ + LDIFImporter *gci; + + gci = (LDIFImporter *) closure; + gci->contactlist = NULL; + gci->iterator = NULL; + gci->ready = FALSE; + + /* Load the book and the cards */ + gci->book = e_book_new (); + if (!gci->book) { + g_message (G_STRLOC ":Couldn't create EBook."); + return FALSE; + } + e_book_load_source (gci->book, gci->primary, TRUE, NULL); + gci->contactlist = create_contacts_from_ldif (filename); + gci->ready = TRUE; + + return TRUE; +} + +static BonoboObject * +factory_fn (BonoboGenericFactory *_factory, + const char *component_id, + void *closure) +{ + EvolutionImporter *importer; + LDIFImporter *gci; + + if (!strcmp (component_id, COMPONENT_IID)) { + gci = g_new (LDIFImporter, 1); + importer = evolution_importer_new (create_control_fn, support_format_fn, + load_file_fn, process_item_fn, NULL, gci); + + g_object_weak_ref (G_OBJECT (importer), + importer_destroy_cb, gci); + + return BONOBO_OBJECT (importer); + } + else { + g_warning (COMPONENT_FACTORY_IID ": Don't know what to do with %s", component_id); + return NULL; + } +} + +BONOBO_ACTIVATION_SHLIB_FACTORY (COMPONENT_FACTORY_IID, "Evolution LDIF importer Factory", factory_fn, NULL) diff --git a/addressbook/importers/evolution-vcard-importer.c b/addressbook/importers/evolution-vcard-importer.c new file mode 100644 index 0000000000..c794d7854a --- /dev/null +++ b/addressbook/importers/evolution-vcard-importer.c @@ -0,0 +1,269 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* Evolution calendar importer component + * + * Copyright (C) 2004 Novell, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU 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 General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Chris Toshok <toshok@ximian.com> + * JP Rosevear <jpr@ximian.com> + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <string.h> + +#include <gtk/gtkcheckbutton.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkvbox.h> +#include <gtk/gtkmain.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkradiobutton.h> +#include <gtk/gtknotebook.h> +#include <bonobo/bonobo-context.h> +#include <bonobo/bonobo-shlib-factory.h> +#include <bonobo/bonobo-control.h> + + +#include <libebook/e-book.h> +//#include <e-book-util.h> + +#include <importer/evolution-importer.h> +#include <importer/GNOME_Evolution_Importer.h> +#include <widgets/misc/e-source-selector.h> + +#include <e-util/e-path.h> + +#define COMPONENT_FACTORY_IID "OAFIID:GNOME_Evolution_Addressbook_VCard_ImporterFactory" +#define COMPONENT_IID "OAFIID:GNOME_Evolution_Addressbook_VCard_Importer" + +typedef struct { + ESource *primary; + + GList *contactlist; + GList *iterator; + EBook *book; + gboolean ready; +} VCardImporter; + +/* EvolutionImporter methods */ +static void +process_item_fn (EvolutionImporter *importer, + CORBA_Object listener, + void *closure, + CORBA_Environment *ev) +{ + VCardImporter *gci = (VCardImporter *) closure; + EContact *contact; + + if (gci->iterator == NULL) + gci->iterator = gci->contactlist; + + if (gci->ready == FALSE) { + GNOME_Evolution_ImporterListener_notifyResult (listener, + GNOME_Evolution_ImporterListener_NOT_READY, + gci->iterator ? TRUE : FALSE, + ev); + return; + } + + if (gci->iterator == NULL) { + GNOME_Evolution_ImporterListener_notifyResult (listener, + GNOME_Evolution_ImporterListener_UNSUPPORTED_OPERATION, + FALSE, ev); + return; + } + + contact = gci->iterator->data; + /* FIXME Error checking */ + e_book_add_contact (gci->book, contact, NULL); + + gci->iterator = gci->iterator->next; + + GNOME_Evolution_ImporterListener_notifyResult (listener, + GNOME_Evolution_ImporterListener_OK, + gci->iterator ? TRUE : FALSE, + ev); + if (ev->_major != CORBA_NO_EXCEPTION) { + g_warning ("Error notifying listeners."); + } + + return; +} + +static char *supported_extensions[3] = { + ".vcf", + ".gcrd", + NULL +}; + +/* Actually check the contents of this file */ +static gboolean +check_file_is_vcard (const char *filename) +{ + FILE *handle; + char line[4096]; + gboolean result; + + handle = fopen (filename, "r"); + if (handle == NULL) { + g_print ("\n"); + return FALSE; + } + + fgets (line, 4096, handle); + if (line == NULL) { + fclose (handle); + g_print ("\n"); + return FALSE; + } + + if (g_ascii_strncasecmp (line, "BEGIN:VCARD", 11) == 0) { + result = TRUE; + } else { + result = FALSE; + } + + fclose (handle); + return result; +} + +static void +primary_selection_changed_cb (ESourceSelector *selector, gpointer data) +{ + VCardImporter *gci = data; + + if (gci->primary) + g_object_unref (gci->primary); + gci->primary = g_object_ref (e_source_selector_peek_primary_selection (selector)); +} + +static void +create_control_fn (EvolutionImporter *importer, Bonobo_Control *control, void *closure) +{ + VCardImporter *gci = closure; + GtkWidget *vbox, *selector; + ESource *primary; + ESourceList *source_list; + + vbox = gtk_vbox_new (FALSE, FALSE); + + /* FIXME Better error handling */ + if (!e_book_get_addressbooks (&source_list, NULL)) + return; + + selector = e_source_selector_new (source_list); + e_source_selector_show_selection (E_SOURCE_SELECTOR (selector), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), selector, FALSE, TRUE, 6); + + /* FIXME What if no sources? */ + primary = e_source_list_peek_source_any (source_list); + e_source_selector_set_primary_selection (E_SOURCE_SELECTOR (selector), primary); + if (!gci->primary) + gci->primary = g_object_ref (primary); + g_object_unref (source_list); + + g_signal_connect (G_OBJECT (selector), "primary_selection_changed", + G_CALLBACK (primary_selection_changed_cb), gci); + + gtk_widget_show_all (vbox); + + *control = BONOBO_OBJREF (bonobo_control_new (vbox)); +} + +static gboolean +support_format_fn (EvolutionImporter *importer, + const char *filename, + void *closure) +{ + char *ext; + int i; + + ext = strrchr (filename, '.'); + if (ext == NULL) { + return check_file_is_vcard (filename); + } + for (i = 0; supported_extensions[i] != NULL; i++) { + if (g_ascii_strcasecmp (supported_extensions[i], ext) == 0) + return check_file_is_vcard (filename); + } + + return FALSE; +} + +static void +importer_destroy_cb (gpointer data, + GObject *where_object_was) +{ + /* FIXME Implement */ +} + +static gboolean +load_file_fn (EvolutionImporter *importer, + const char *filename, + void *closure) +{ + VCardImporter *gci; + + if (check_file_is_vcard (filename) == FALSE) { + return FALSE; + } + + gci = (VCardImporter *) closure; + gci->contactlist = NULL; + gci->iterator = NULL; + gci->ready = FALSE; + + /* Load the book and the cards */ + gci->book = e_book_new (); + if (!gci->book) { + g_message (G_STRLOC ":Couldn't create EBook."); + return FALSE; + } + e_book_load_source (gci->book, gci->primary, TRUE, NULL); +// gci->cardlist = e_card_load_cards_from_file_with_default_charset(filename, "ISO-8859-1"); + gci->ready = TRUE; + + return TRUE; +} + +static BonoboObject * +factory_fn (BonoboGenericFactory *_factory, + const char *component_id, + void *closure) +{ + EvolutionImporter *importer; + VCardImporter *gci; + + if (!strcmp (component_id, COMPONENT_IID)) { + gci = g_new (VCardImporter, 1); + importer = evolution_importer_new (create_control_fn, support_format_fn, + load_file_fn, process_item_fn, NULL, gci); + + g_object_weak_ref (G_OBJECT (importer), + importer_destroy_cb, gci); + return BONOBO_OBJECT (importer); + } + else { + g_warning (COMPONENT_FACTORY_IID ": Don't know what to do with %s", component_id); + return NULL; + } +} + +BONOBO_ACTIVATION_SHLIB_FACTORY (COMPONENT_FACTORY_IID, "Evolution VCard Importer Factory", factory_fn, NULL) |