]> git.deb.at Git - pkg/abook.git/blobdiff - filter.c
- replace abook_malloc, abook_realloc and my_free with new xmalloc routines
[pkg/abook.git] / filter.c
index 4489839470e5b2eb6a9957c3a5d6a06ce083014c..e11a60e18ee9bfb35a26ead350449e67677a21cb 100644 (file)
--- a/filter.c
+++ b/filter.c
@@ -2,7 +2,7 @@
 /*
  * $Id$
  *
- * by JH <jheinonen@bigfoot.com>
+ * by JH <jheinonen@users.sourceforge.net>
  *
  * Copyright (C) Jaakko Heinonen
  */
@@ -12,6 +12,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <pwd.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include "abook_curses.h"
 #include "filter.h"
@@ -21,6 +22,8 @@
 #include "list.h"
 #include "misc.h"
 #include "options.h"
+#include "xmalloc.h"
+#include <assert.h>
 
 extern int items;
 extern list_item *database;
@@ -30,30 +33,47 @@ extern struct abook_field abook_fields[];
  * function declarations
  */
 
+/*
+ * import filter prototypes
+ */
+
 static int      ldif_parse_file(FILE *handle);
 static int     mutt_parse_file(FILE *in);
 static int     pine_parse_file(FILE *in);
+static int     csv_parse_file(FILE *in);
+static int     allcsv_parse_file(FILE *in);
 
-static int      ldif_export_database(FILE *out);
-static int     html_export_database(FILE *out);
-static int     pine_export_database(FILE *out);
-static int     csv_export_database(FILE *out);
-static int     gcrd_export_database(FILE *out);
-static int     mutt_alias_export(FILE *out);
-static int     elm_alias_export(FILE *out);
-static int     text_export_database(FILE *out);
-static int     spruce_export_database(FILE *out);
+/*
+ * export filter prototypes
+ */
 
+static int      ldif_export_database(FILE *out, struct db_enumerator e);
+static int     html_export_database(FILE *out, struct db_enumerator e);
+static int     pine_export_database(FILE *out, struct db_enumerator e);
+static int     csv_export_database(FILE *out, struct db_enumerator e);
+static int     allcsv_export_database(FILE *out, struct db_enumerator e);
+static int     palm_export_database(FILE *out, struct db_enumerator e);
+static int     gcrd_export_database(FILE *out, struct db_enumerator e);
+static int     mutt_alias_export(FILE *out, struct db_enumerator e);
+static int     elm_alias_export(FILE *out, struct db_enumerator e);
+static int     text_export_database(FILE *out, struct db_enumerator e);
+static int     spruce_export_database(FILE *out, struct db_enumerator e);
 
-struct abook_filter i_filters[] = {
+/*
+ * end of function declarations
+ */
+
+struct abook_input_filter i_filters[] = {
        { "abook", "abook native format", parse_database },
        { "ldif", "ldif / Netscape addressbook", ldif_parse_file },
-       { "mutt", "mutt alias (beta)", mutt_parse_file },
+       { "mutt", "mutt alias", mutt_parse_file },
        { "pine", "pine addressbook", pine_parse_file },
+       { "csv", "comma separated values", csv_parse_file },
+       { "allcsv", "comma separated all values", allcsv_parse_file },
        { "\0", NULL, NULL }
 };
 
-struct abook_filter e_filters[] = {
+struct abook_output_filter e_filters[] = {
        { "abook", "abook native format", write_database },
        { "ldif", "ldif / Netscape addressbook (.4ld)", ldif_export_database },
        { "mutt", "mutt alias", mutt_alias_export },
@@ -61,6 +81,8 @@ struct abook_filter e_filters[] = {
        { "pine", "pine addressbook", pine_export_database },
        { "gcrd", "GnomeCard (VCard) addressbook", gcrd_export_database },
        { "csv", "comma separated values", csv_export_database },
+       { "allcsv", "comma separated all values", allcsv_export_database },
+       { "palmcsv", "Palm comma separated values", palm_export_database},
        { "elm", "elm alias", elm_alias_export },
        { "text", "plain text", text_export_database },
        { "spruce", "Spruce address book", spruce_export_database },
@@ -92,11 +114,22 @@ print_filters()
 }
 
 static int
-number_of_filters(struct abook_filter * filters)
+number_of_output_filters()
+{
+       int i;
+
+       for(i=0; *e_filters[i].filtname ; i++)
+               ;
+
+       return i;
+}
+
+static int
+number_of_input_filters()
 {
        int i;
 
-       for(i=0; *filters[i].filtname ; i++)
+       for(i=0; *i_filters[i].filtname ; i++)
                ;
 
        return i;
@@ -112,7 +145,7 @@ get_real_name()
 
        pwent = getpwnam(username);
 
-       if( (tmp = malloc(strlen(pwent->pw_gecos) +1)) == NULL)
+       if((tmp = strdup(pwent->pw_gecos)) == NULL)
                return strdup(username);
 
        rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
@@ -160,15 +193,15 @@ import_database()
        import_screen();
        
        filter = getch() - 'a';
-       if(filter == 'x' - 'a' || filter >= number_of_filters(e_filters) ||
-                       filter < 0) {
+       if(filter == 'x' - 'a' ||
+               filter >= number_of_input_filters() || filter < 0) {
                refresh_screen();
                return 1;
        }
        
        mvaddstr(5+filter, 2, "->");
        
-       filename = ask_filename("Filename: ", 1);
+       filename = ask_filename("Filename: ");
        if( !filename ) {
                refresh_screen();
                return 2;
@@ -176,8 +209,7 @@ import_database()
                
        if(  i_read_file(filename, i_filters[filter].func ) )
                statusline_msg("Error occured while opening the file");
-       else
-       if( tmp == items )
+       else if( tmp == items )
                statusline_msg("Hmm.., file seems not to be a valid file");
        
        refresh_screen();
@@ -194,7 +226,7 @@ i_read_file(char *filename, int (*func) (FILE *in))
        FILE *in;
        int ret = 0;
 
-       if( ( in = fopen( filename, "r" ) ) == NULL )
+       if( ( in = abook_fopen( filename, "r" ) ) == NULL )
                return 1;
 
        ret = (*func) (in);
@@ -205,14 +237,15 @@ i_read_file(char *filename, int (*func) (FILE *in))
 }
 
 int
-import(char filtname[FILTNAME_LEN], char *filename)
+import_file(char filtname[FILTNAME_LEN], char *filename)
 {
        int i;
        int tmp = items;
        int ret = 0;
 
        for(i=0;; i++) {
-               if( ! strncmp(i_filters[i].filtname, filtname, FILTNAME_LEN) )
+               if( ! strncasecmp(i_filters[i].filtname, filtname,
+                                       FILTNAME_LEN) )
                        break;
                if( ! *i_filters[i].filtname ) {
                        i = -1;
@@ -223,9 +256,13 @@ import(char filtname[FILTNAME_LEN], char *filename)
        if( i<0 )
                return -1;
 
-       if( !strcmp(filename, "-") )
-               ret = (*i_filters[i].func) (stdin);
-       else
+       if( !strcmp(filename, "-") ) {
+               struct stat s;
+               if( (fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
+                       ret = 1;
+               else
+                       ret = (*i_filters[i].func) (stdin);
+       } else
                ret =  i_read_file(filename, i_filters[i].func);
        
        if( tmp == items )
@@ -238,7 +275,8 @@ import(char filtname[FILTNAME_LEN], char *filename)
  * export
  */
 
-static int             e_write_file(char *filename, int (*func) (FILE *in));
+static int             e_write_file(char *filename,
+               int (*func) (FILE *in, struct db_enumerator e), int mode);
 
 static void
 export_screen()
@@ -266,26 +304,40 @@ int
 export_database()
 {
        int filter;
+       int enum_mode = ENUM_ALL;
        char *filename;
 
        export_screen();
        
        filter = getch() - 'a';
-       if(filter == 'x' - 'a' || filter >= number_of_filters(e_filters) ||
-                       filter < 0) {
+       if(filter == 'x' - 'a' ||
+               filter >= number_of_output_filters() || filter < 0) {
                refresh_screen();
                return 1;
        }
        
        mvaddstr(5+filter, 2, "->");
+
+       if( selected_items() ) {
+               statusline_addstr("Export All/Selected/Cancel (A/s/c)");
+               switch( tolower(getch()) ) {
+                       case 's':
+                               enum_mode = ENUM_SELECTED;
+                               break;
+                       case 'c':
+                               clear_statusline();
+                               return 1;
+               }
+               clear_statusline();
+       }
        
-       filename = ask_filename("Filename: ", 0);
+       filename = ask_filename("Filename: ");
        if( !filename ) {
                refresh_screen();
                return 2;
        }
        
-       if(  e_write_file(filename, e_filters[filter].func ) )
+       if(  e_write_file(filename, e_filters[filter].func, enum_mode ) )
                statusline_msg("Error occured while exporting");
        
        refresh_screen();
@@ -295,10 +347,12 @@ export_database()
 }
 
 static int
-e_write_file(char *filename, int (*func) (FILE *in))
+e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
+               int mode)
 {
        FILE *out;
        int ret = 0;
+       struct db_enumerator enumerator = init_db_enumerator(mode);
 
        if( (out = fopen(filename, "a")) == NULL )
                return 1;
@@ -306,7 +360,7 @@ e_write_file(char *filename, int (*func) (FILE *in))
        if( ftell(out) )
                return 1;
 
-       ret = (*func) (out);
+       ret = (*func) (out, enumerator);
        
        fclose(out);
        
@@ -314,12 +368,14 @@ e_write_file(char *filename, int (*func) (FILE *in))
 }
 
 int
-fexport(char filtname[FILTNAME_LEN], FILE *handle)
+fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
 {
        int i;
+       struct db_enumerator e = init_db_enumerator(enum_mode);
 
        for(i=0;; i++) {
-               if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) )
+               if( ! strncasecmp(e_filters[i].filtname, filtname,
+                                       FILTNAME_LEN) )
                        break;
                if( ! *e_filters[i].filtname ) {
                        i = -1;
@@ -327,19 +383,22 @@ fexport(char filtname[FILTNAME_LEN], FILE *handle)
                }
        }
 
-       return (e_filters[i].func) (handle);
+       return (e_filters[i].func) (handle, e);
 }
 
-       
+
 
 int
-export(char filtname[FILTNAME_LEN], char *filename)
+export_file(char filtname[FILTNAME_LEN], char *filename)
 {
+       const int mode = ENUM_ALL;
        int i;
        int ret = 0;
+       struct db_enumerator e = init_db_enumerator(mode);
        
        for(i=0;; i++) {
-               if( ! strncmp(e_filters[i].filtname, filtname, FILTNAME_LEN) )
+               if( ! strncasecmp(e_filters[i].filtname, filtname,
+                                       FILTNAME_LEN) )
                        break;
                if( ! *e_filters[i].filtname ) {
                        i = -1;
@@ -351,9 +410,9 @@ export(char filtname[FILTNAME_LEN], char *filename)
                return -1;
 
        if( !strcmp(filename, "-") )
-               ret = (e_filters[i].func) (stdout);
+               ret = (e_filters[i].func) (stdout, e);
        else
-               ret =  e_write_file(filename, e_filters[i].func);
+               ret =  e_write_file(filename, e_filters[i].func, mode);
 
        return ret;
 }
@@ -370,11 +429,7 @@ export(char filtname[FILTNAME_LEN], char *filename)
 
 static void    ldif_fix_string(char *str);
 
-#ifndef LINESIZE
-#      define LINESIZE 1024
-#endif
-
-#define        LDIF_ITEM_FIELDS        15
+#define        LDIF_ITEM_FIELDS        16
 
 typedef char*  ldif_item[LDIF_ITEM_FIELDS];
 
@@ -382,6 +437,7 @@ static ldif_item ldif_field_names = {
        "cn",   
        "mail",
        "streetaddress",
+       "streetaddress2",
         "locality",
        "st",
        "postalcode",
@@ -400,6 +456,7 @@ static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
        NAME,           /* "cn" */
        EMAIL,          /* "mail" */
        ADDRESS,        /* "streetaddress" */
+       ADDRESS2,       /* "streetaddress2" */     
         CITY,          /* "locality" */
        STATE,          /* "st" */
        ZIP,            /* "postalcode" */
@@ -418,48 +475,45 @@ static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
 static char * 
 ldif_read_line(FILE *in)
 {
-       char line[LINESIZE];
-       char *buf=NULL;
+       char *buf = NULL;
        char *ptr, *tmp;
        long pos;
        int i;
 
-       for(i=1;;i++) {
+       for(i = 1;;i++) {
+               char *line;
+
                pos = ftell(in);
-               fgets(line, LINESIZE, in);
+               line = getaline(in);
                
-               if( feof(in) )
+               if( feof(in) || !line )
                        break;
                
                if(i == 1) {
-                       buf = strdup(line);
+                       buf = line;
                        continue;
                }
-               
+
                if(*line != ' ') {
-                       fseek(in, pos, SEEK_SET);
+                       fseek(in, pos, SEEK_SET); /* fixme ! */
+                       free(line);
                        break;
                }
 
-               ptr = (char *)&line;
+               ptr = line;
                while( *ptr == ' ')
                        ptr++;
 
                tmp = buf;
                buf = strconcat(buf, ptr, NULL);
                free(tmp);
+               free(line);
        }
 
-       if( *buf == '#' ) {
+       if(buf && *buf == '#' ) {
                free(buf);
                return NULL;
        }
-               
-       if(buf) {
-               int i,j;
-               for(i=0,j=0; j < strlen(buf); i++, j++)
-                       buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
-       }
 
        return buf;
 }
@@ -471,10 +525,10 @@ ldif_add_item(ldif_item ldif_item)
        int i;
 
        memset(abook_item, 0, sizeof(abook_item));
-       
+
        if( !ldif_item[LDIF_ITEM_FIELDS -1] )
                goto bail_out;
-       
+
 
        for(i=0; i < LDIF_ITEM_FIELDS; i++) {
                if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] )
@@ -485,7 +539,7 @@ ldif_add_item(ldif_item ldif_item)
 
 bail_out:
        for(i=0; i < LDIF_ITEM_FIELDS; i++)
-               my_free(ldif_item[i]);
+               xfree(ldif_item[i]);
 
 }
 
@@ -505,7 +559,7 @@ ldif_convert(ldif_item item, char *type, char *value)
                                if( safe_strcmp("person", value))
                                        break;
                        if(item[i])
-                               my_free(item[i]);
+                               xfree(item[i]);
                        item[i] = strdup(value);
                }
        }
@@ -526,15 +580,15 @@ ldif_parse_file(FILE *handle)
                        continue;
 
                if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) {
-                       my_free(line);
+                       xfree(line);
                        continue; /* just skip the errors */
                }
-                               
+
                ldif_fix_string(value);
 
                ldif_convert(item, type, value);
 
-               my_free(line);
+               xfree(line);
        } while ( !feof(handle) );
 
        ldif_convert(item, "dn", "");
@@ -547,7 +601,7 @@ ldif_fix_string(char *str)
 {
        int i, j;
 
-       for( i = 0, j = 0; j < strlen(str); i++, j++)
+       for( i = 0, j = 0; j < (int)strlen(str); i++, j++)
                str[i] = ( str[j] == (char)0xc3 ?
                                (char) str[++j] + (char) 0x40 :
                                str[j] );
@@ -563,38 +617,25 @@ ldif_fix_string(char *str)
  * mutt alias import filter
  */
 
-enum {
-       MUTT_ALIAS,
-       MUTT_NAME,
-       MUTT_EMAIL
-};
-
-static void
-remove_newlines(char *buf)
-{
-       int i,j;
-       
-       for(i=0,j=0; j < strlen(buf); i++, j++)
-               buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
-}
+#include "getname.h"
 
 static int
 mutt_read_line(FILE *in, char **alias, char **rest)
 {
-       char line[LINESIZE];
-       char *ptr=(char *)&line;
-       char *tmp;
+       char *line, *ptr, *tmp;
+       size_t alias_len;
 
-       fgets(line, LINESIZE, in);
-       remove_newlines(line);
+       if( !(line = ptr = getaline(in)) )
+               return 1; /* error / EOF */
 
        while( ISSPACE(*ptr) )
                ptr++;
 
        if( strncmp("alias", ptr, 5) ) {
+               free(line);
                return 1;
        }
-               
+
        ptr += 5;
 
        while( ISSPACE(*ptr) )
@@ -605,93 +646,113 @@ mutt_read_line(FILE *in, char **alias, char **rest)
        while( ! ISSPACE(*ptr) )
                ptr++;
 
-       if( (*alias = malloc(ptr-tmp+1)) == NULL)
+       /* includes also the trailing zero */
+       alias_len = (size_t)(ptr - tmp + 1);
+
+       if( (*alias = xmalloc(alias_len)) == NULL) {
+               free(line);
                return 1;
+       }
 
-       strncpy(*alias, tmp, ptr-tmp);
-       *(*alias+(ptr-tmp)) = 0;
+       strncpy(*alias, tmp, alias_len - 1);
+       *(*alias + alias_len - 1) = 0;
 
-       while( ISSPACE(*ptr) )
+       while(ISSPACE(*ptr))
                ptr++;
 
        *rest = strdup(ptr);    
-       
+
+       free(line);
        return 0;
 }
 
 static void
-mutt_parse_email(char *mutt_item[3])
+mutt_fix_quoting(char *p)
 {
-       char *tmp;
-       int i;
+       char *escape = 0;
 
-       if( (tmp = strchr(mutt_item[MUTT_NAME], '<')) )
-               *tmp = 0;
-       else
-               return;
-
-       mutt_item[MUTT_EMAIL] = strdup(tmp+1);
-
-       if( (tmp = strchr(mutt_item[MUTT_EMAIL], '>')) )
-               *tmp = 0;
-
-       tmp = mutt_item[MUTT_NAME];
-
-       for(i=strlen(tmp)-1; i>0; i--)
-               if(ISSPACE(tmp[i]))
-                       tmp[i] = 0;
-               else
-                       break;
-
-       mutt_item[MUTT_NAME] = strdup(tmp);
-
-       free(tmp);
+       for(; *p; p++) {
+               switch(*p) {
+                       case '\"':
+                               if(escape)
+                                       *escape = ' ';
+                               break;
+                       case '\\':
+                               escape = p;
+                               break;
+                       default:
+                               escape = 0;
+               }
+       }
 }
 
 static void
-mutt_add_mutt_item(char *mutt_item[3])
+mutt_parse_email(list_item item)
 {
-       list_item abook_item;
+       char *line = item[NAME];
+       char *tmp;
+       char *name, *email;
+#if 0
+       char *start = line;
+       int i = 0;
+#endif
 
-       memset(abook_item, 0, sizeof(abook_item));
+       mutt_fix_quoting(line);
+       tmp = strconcat("From: ", line, NULL);
+       getname(tmp, &name, &email);
+       free(tmp);
 
-       abook_item[NAME] = safe_strdup(mutt_item[MUTT_NAME]);
-       abook_item[EMAIL] = safe_strdup(mutt_item[MUTT_EMAIL]);
-       abook_item[NICK] = safe_strdup(mutt_item[MUTT_ALIAS]);
+       if(name)
+               item[NAME] = name;
+       else
+               return;
+       if(email)
+               item[EMAIL] = email;
+       else
+               return;
 
-       add_item2database(abook_item);
+       /*
+        * this is completely broken
+        */
+#if 0
+       while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
+               tmp = strconcat("From: ", ++start, NULL);
+               getname(tmp, &name, &email);
+               free(tmp);
+               free(name);
+               if(email) {
+                       if(*email) {
+                               tmp = strconcat(item[EMAIL], ",", email, NULL);
+                               free(item[EMAIL]);
+                               item[EMAIL] = tmp;
+                       } else {
+                               xfree(email);
+                       }
+               }
+       }
+#endif
 }
 
 static int
 mutt_parse_file(FILE *in)
 {
-       char *mutt_item[3];
+       list_item item;
 
        for(;;) {
+               memset(item, 0, sizeof(item));
 
-               memset(mutt_item, 0, sizeof(mutt_item) );
-               
-               if( mutt_read_line(in, &mutt_item[MUTT_ALIAS],
-                               &mutt_item[MUTT_NAME]) )
-                       continue;
-
-               mutt_parse_email(mutt_item);
+               if( !mutt_read_line(in, &item[NICK],
+                               &item[NAME]) )
+                       mutt_parse_email(item);
 
                if( feof(in) ) {
-                       free(mutt_item[MUTT_ALIAS]);
-                       free(mutt_item[MUTT_NAME]);
-                       free(mutt_item[MUTT_EMAIL]);
+                       free_list_item(item);
                        break;
                }
 
-               mutt_add_mutt_item(mutt_item);
-
-               free(mutt_item[MUTT_ALIAS]);
-               free(mutt_item[MUTT_NAME]);
-               free(mutt_item[MUTT_EMAIL]);
+               add_item2database(item);
        }
 
-
        return 0;
 }
 
@@ -699,6 +760,7 @@ mutt_parse_file(FILE *in)
  * end of mutt alias import filter
  */
 
+
 /*
  * ldif export filter
  */
@@ -716,18 +778,18 @@ ldif_fput_type_and_value(FILE *out,char *type, char *value )
 }
 
 static int
-ldif_export_database(FILE *out)
+ldif_export_database(FILE *out, struct db_enumerator e)
 {
-       int i;
        char email[MAX_EMAILSTR_LEN];
 
        fprintf(out, "version: 1\n");
-       for(i=0; i<items; i++) {
+
+       db_enumerate_items(e) {
                char *tmp;
                int j;
-               get_first_email(email, i);
+               get_first_email(email, e.item);
 
-               tmp = mkstr("cn=%s,mail=%s", database[i][NAME], email);
+               tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
                ldif_fput_type_and_value(out, "dn", tmp);
                free(tmp);
 
@@ -736,10 +798,10 @@ ldif_export_database(FILE *out)
                                if(ldif_conv_table[j] == EMAIL)
                                        ldif_fput_type_and_value(out,
                                                ldif_field_names[j], email);
-                               else if(database[i][ldif_conv_table[j]])
+                               else if(database[e.item][ldif_conv_table[j]])
                                        ldif_fput_type_and_value(out,
                                                ldif_field_names[j],
-                                               database[i][ldif_conv_table[j]]);
+                                               database[e.item][ldif_conv_table[j]]);
                        }
                }
 
@@ -761,12 +823,12 @@ ldif_export_database(FILE *out)
 static void            html_export_write_head(FILE *out, int extra_column);
 static void            html_export_write_tail(FILE *out);
 
+extern int extra_column;
+
 static int
-html_export_database(FILE *out)
+html_export_database(FILE *out, struct db_enumerator e)
 {
        char tmp[MAX_EMAILSTR_LEN];
-       int i;
-       int extra_column = options_get_int("extra_column");
 
        if( items < 1 )
                return 2;
@@ -775,17 +837,23 @@ html_export_database(FILE *out)
                extra_column : PHONE;
 
        html_export_write_head(out, extra_column);
-       for( i = 0; i < items; i++ ) {
-               get_first_email(tmp, i);
-               fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
-                               tmp,
-                               database[i][NAME] );
-                               
+
+       db_enumerate_items(e) {
+               get_first_email(tmp, e.item);
+               if (*tmp)
+                   fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
+                           tmp,
+                           database[e.item][NAME] );
+               else
+                   fprintf(out, "<tr>\n<td>%s\n",
+                           database[e.item][NAME] );
+
                fprintf(out, "<td>%s\n<td>%s\n",
-                               database[i][EMAIL],
-                               safe_str(database[i][extra_column]) );
+                               database[e.item][EMAIL],
+                               safe_str(database[e.item][extra_column]) );
                fprintf(out, "</tr>\n\n");
        }
+
        html_export_write_tail(out);
 
        return 0;
@@ -797,13 +865,13 @@ html_export_write_head(FILE *out, int extra_column)
 {
        char *realname = get_real_name();
 
-       fprintf(out, "<html>\n<head>\n  <title>%s's addressbook</title>",
-                       realname );
+       fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
+       fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>", realname );
        fprintf(out, "\n</head>\n<body>\n");
        fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
        fprintf(out, "<br><br>\n\n");
 
-       fprintf(out, "<center><table border>\n");
+       fprintf(out, "<table border=\"1\" align=\"center\">\n");
        fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
                        abook_fields[extra_column].name);
 
@@ -813,7 +881,7 @@ html_export_write_head(FILE *out, int extra_column)
 static void
 html_export_write_tail(FILE *out)
 {
-       fprintf(out, "\n</table></center>\n");
+       fprintf(out, "\n</table>\n");
        fprintf(out, "\n</body>\n</html>\n");
 }
        
@@ -821,16 +889,19 @@ html_export_write_tail(FILE *out)
  * end of html export filter
  */
 
+
 /*
  * pine addressbook import filter
  */
 
+#define PINE_BUF_SIZE 2048
+
 static void
 pine_fixbuf(char *buf)
 {
        int i,j;
 
-       for(i=0,j=0; j < strlen(buf); i++, j++)
+       for(i=0,j=0; j < (int)strlen(buf); i++, j++)
                buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
 }
 
@@ -848,9 +919,9 @@ pine_convert_emails(char *s)
 
        if( ( tmp = strchr(s,')')) )
                *tmp=0;
-       
+
        for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
-               if( i > 3 ) {
+               if( i > MAX_EMAILS - 1 ) {
                        *tmp = 0;
                        break;  
                }
@@ -863,32 +934,33 @@ pine_parse_buf(char *buf)
        list_item item;
        char *start = buf;
        char *end;
-       char tmp[400];
+       char tmp[PINE_BUF_SIZE];
        int i, len, last;
        int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
 
-       memset(&item, 0, sizeof(item) );
+       memset(&item, 0, sizeof(item));
        
        for(i=0, last=0; !last ; i++) {
                if( ! (end = strchr(start, '\t')) )
                        last=1;
-               
+
                len = last ? strlen(start) : (int) (end-start);
-               len = min(len, 400-1);
-       
-               if(i < sizeof(pine_conv_table) / sizeof(*pine_conv_table)
+               len = min(len, PINE_BUF_SIZE - 1);
+
+               if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
                                && pine_conv_table[i] >= 0) {
                        strncpy(tmp, start, len);
                        tmp[len] = 0;
-                       item[pine_conv_table[i]] = strdup(tmp);
+                       if(*tmp)
+                               item[pine_conv_table[i]] = strdup(tmp);
                }
                start = end + 1;
        }
-       
+
        pine_convert_emails(item[EMAIL]);
        add_item2database(item);
 }
-               
+
 
 #define LINESIZE       1024
 
@@ -896,33 +968,36 @@ static int
 pine_parse_file(FILE *in)
 {
        char line[LINESIZE];
-       char *buf=NULL;
+       char *buf = NULL;
        char *ptr;
        int i;
 
        fgets(line, LINESIZE, in);      
-       
+
        while(!feof(in)) {
-               for(i=2;;i++) {
-                       buf = realloc(buf, i*LINESIZE);
-                       if(i==2)
+               for(i = 2;;i++) {
+                       buf = xrealloc(buf, i*LINESIZE);
+                       if(i == 2)
                                strcpy(buf, line);
                        fgets(line, LINESIZE, in);
                        ptr=(char *)&line;
                        if(*ptr != ' ' || feof(in) )
                                break;
                        else
-                               while( *ptr == ' ') ptr++;
-                               
+                               while( *ptr == ' ')
+                                       ptr++;
+
                        strcat(buf, ptr);
                }
-               if( *buf == '#' )
+               if( *buf == '#' ) {
+                       xfree(buf);
                        continue;
+               }
                pine_fixbuf(buf);
 
                pine_parse_buf(buf);
 
-               my_free(buf);
+               xfree(buf);
        }
 
        return 0;
@@ -932,6 +1007,7 @@ pine_parse_file(FILE *in)
  * end of pine addressbook import filter
  */
 
+
 /*
  * pine addressbook export filter
  *
@@ -940,17 +1016,15 @@ pine_parse_file(FILE *in)
  */
 
 static int
-pine_export_database(FILE *out)
+pine_export_database(FILE *out, struct db_enumerator e)
 {
-       int i;
-
-       for(i=0; i < items; i++ ) {
-               fprintf(out, have_multiple_emails(i) ?
+       db_enumerate_items(e) {
+               fprintf(out, have_multiple_emails(e.item) ?
                                "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
-                               safe_str(database[i][NICK]),
-                               safe_str(database[i][NAME]),
-                               safe_str(database[i][EMAIL]),
-                               safe_str(database[i][NOTES])
+                               safe_str(database[e.item][NICK]),
+                               safe_str(database[e.item][NAME]),
+                               safe_str(database[e.item][EMAIL]),
+                               safe_str(database[e.item][NOTES])
                                );
        }
 
@@ -963,91 +1037,515 @@ pine_export_database(FILE *out)
 
 
 /*
- * csv addressbook export filter
+ * csv import filter
  */
 
+/* FIXME
+ * these files should be parsed according to a certain
+ * lay out, or the default if layout is not given, at 
+ * the moment only default is done...
+ */ 
+
+#define CSV_COMMENT_CHAR       '#'
+
+static int csv_conv_table[] = {
+       NAME,
+       EMAIL,
+       PHONE,
+       NOTES,
+       NICK
+};
+
+static int allcsv_conv_table[] = {
+       NAME,
+       EMAIL,
+       ADDRESS,
+       ADDRESS2,
+       CITY,
+       STATE,
+       ZIP,
+       COUNTRY,
+       PHONE,
+       WORKPHONE,
+       FAX,
+       MOBILEPHONE,
+       NICK,
+       URL,
+       NOTES,
+       CUSTOM1,
+       CUSTOM2,
+       CUSTOM3,
+       CUSTOM4,
+       CUSTOM5,
+};
+
+static void
+csv_convert_emails(char *s)
+{
+       int i;
+       char *tmp;
+
+       if( s == NULL )
+               return;
+
+       for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
+               if( i > MAX_EMAILS - 1 ) {
+                       *tmp = 0;
+                       break;  
+               }
+
+}
+
+static char *
+csv_remove_quotes(char *s)
+{
+       char *copy, *trimmed;
+       int len;
+
+       copy = trimmed = strdup(s);
+       strtrim(trimmed);
+
+       len = strlen(trimmed);
+       if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
+               if(len < 3) {
+                       xfree(copy);
+                       return NULL;
+               }
+               trimmed[len - 1] = 0;
+               trimmed++;
+               trimmed = strdup(trimmed);
+               free(copy);
+               return trimmed;
+       }
+
+       xfree(copy);
+       return strdup(s);
+}
+
+static void
+csv_store_field(list_item item, char *s, int field)
+{
+       char *newstr = NULL;
+
+       if(!s || !*s)
+               return;
+
+       if( !(newstr = csv_remove_quotes(s)) )
+               return;
+
+       if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table))
+                       && csv_conv_table[field] >= 0) {
+               item[csv_conv_table[field]] = newstr;
+       } else {
+               xfree(newstr);
+       }
+}
+
+static void
+allcsv_store_field(list_item item, char *s, int field)
+{
+       char *newstr = NULL;
+
+       if(!s || !*s)
+               return;
+
+       if( !(newstr = csv_remove_quotes(s)) )
+               return;
+
+       if(field < (int)(sizeof(allcsv_conv_table) / sizeof(*allcsv_conv_table))
+                       && allcsv_conv_table[field] >= 0) {
+               item[allcsv_conv_table[field]] = newstr;
+       } else {
+               xfree(newstr);
+       }
+}
+
 static int
-csv_export_database(FILE *out)
+csv_is_valid_quote_end(char *p)
+{
+       if(*p != '\"')
+               return FALSE;
+
+       for(p++; *p; p++) {
+               if(*p == ',')
+                       return TRUE;
+               else if(!ISSPACE(*p))
+                       return FALSE;
+       }
+
+       return TRUE;
+}
+
+static int
+csv_is_valid_quote_start(char *p)
+{
+       for(; *p; p++) {
+               if(*p == '\"')
+                       return TRUE;
+               else if(!ISSPACE(*p))
+                       return FALSE;
+       }
+
+       return FALSE;
+}
+
+static void
+csv_parse_line(char *line)
+{
+       char *p, *start;
+       int field;
+       bool in_quote = FALSE;
+       list_item item;
+
+       memset(item, 0, sizeof(item));
+
+       for(p = start = line, field = 0; *p; p++) {
+               if(in_quote) {
+                       if(csv_is_valid_quote_end(p))
+                               in_quote = FALSE;
+               } else {
+                       if ( (((p - start) / sizeof (char)) < 2 ) &&
+                               csv_is_valid_quote_start(p) )
+                               in_quote = TRUE;
+               }
+
+               if( *p == ',' && !in_quote) {
+                       *p = 0;
+                       csv_store_field(item, start, field);
+                       field++;
+                       start = p + 1;
+               }
+       }
+       /*
+        * store last field
+        */
+       csv_store_field(item, start, field);
+
+       csv_convert_emails(item[EMAIL]);
+       add_item2database(item);
+}
+
+static void
+allcsv_parse_line(char *line)
+{
+       char *p, *start;
+       int field;
+       bool in_quote = FALSE;
+       list_item item;
+
+       memset(item, 0, sizeof(item));
+
+       for(p = start = line, field = 0; *p; p++) {
+               if(in_quote) {
+                       if(csv_is_valid_quote_end(p))
+                               in_quote = FALSE;
+               } else {
+                       if ( (((p - start) / sizeof (char)) < 2 ) &&
+                               csv_is_valid_quote_start(p) )
+                               in_quote = TRUE;
+               }
+
+               if( *p == ',' && !in_quote) {
+                       *p = 0;
+                       allcsv_store_field(item, start, field);
+                       field++;
+                       start = p + 1;
+               }
+       }
+       /*
+        * store last field
+        */
+       allcsv_store_field(item, start, field);
+
+       csv_convert_emails(item[EMAIL]);
+       add_item2database(item);
+}
+
+
+static int
+csv_parse_file(FILE *in)
+{
+       char *line = NULL;
+
+       while(!feof(in)) {
+               line = getaline(in);
+
+               if(line && *line && *line != CSV_COMMENT_CHAR)
+                       csv_parse_line(line);
+
+               xfree(line);
+       }
+
+       return 0;
+}
+
+static int
+allcsv_parse_file(FILE *in)
+{
+       char *line = NULL;
+
+       while(!feof(in)) {
+               line = getaline(in);
+
+               if(line && *line && *line != CSV_COMMENT_CHAR)
+                       allcsv_parse_line(line);
+
+               xfree(line);
+       }
+
+       return 0;
+}
+
+/*
+ * end of csv import filter
+ */
+
+/*
+ * csv addressbook export filters
+ */
+
+#define CSV_LAST               (-1)
+#define CSV_UNDEFINED          (-2)
+#define CSV_SPECIAL(X)         (-3 - (X))
+#define CSV_IS_SPECIAL(X)      ((X) <= -3)
+
+static int
+csv_export_common(FILE *out, struct db_enumerator e,
+               int fields[], void (*special_func)(FILE *, int, int))
+{
+       int i;
+
+       db_enumerate_items(e) {
+               for(i = 0; fields[i] != CSV_LAST; i++) {
+                       if(fields[i] == CSV_UNDEFINED)
+                               fprintf(out, "\"\"");
+                       else if(CSV_IS_SPECIAL(fields[i])) {
+                               if(special_func)
+                                       (*special_func)(out, e.item, fields[i]);
+                       } else
+                               /*fprintf(out,(
+                       strchr(safe_str(database[e.item][fields[i]]), ',') ||
+                       strchr(safe_str(database[e.item][fields[i]]), '\"')) ?
+                               "\"%s\"" : "%s",
+                               safe_str(database[e.item][fields[i]])
+                               );*/
+                               fprintf(out, "\"%s\"",
+                                       safe_str(database[e.item][fields[i]]));
+
+                       if(fields[i + 1] != CSV_LAST)
+                               fputc(',', out);
+               }
+               fputc('\n', out);
+       }
+
+       return 0;
+}
+
+static int
+csv_export_database(FILE *out, struct db_enumerator e)
 {
-       int i, j;
        int csv_export_fields[] = {
                NAME,
                EMAIL,
                PHONE,
                NOTES,
-               -1
+               NICK,
+               CSV_LAST
        };
 
-       for(i=0; i < items; i++ ) {
-               for(j = 0; csv_export_fields[j] >= 0; j++) {
-                       fprintf(out, strchr(safe_str(database[i][csv_export_fields[j]]), ',') ?
-                               "\"%s\"" : "%s",
-                               safe_str(database[i][csv_export_fields[j]])
-                               );
-                       if(csv_export_fields[j+1] >= 0)
-                               fputc(',', out);
-               }
-               fputc('\n', out);
-       }
-               
+       csv_export_common(out, e, csv_export_fields, NULL);
+       
+       return 0;
+}
 
+static int
+allcsv_export_database(FILE *out, struct db_enumerator e)
+{
+       /*
+        * TODO: Should get these atomatically from abook_fileds
+        *  - JH
+        */
+       int allcsv_export_fields[] = {
+               NAME,
+               EMAIL,
+               ADDRESS,
+               ADDRESS2,
+               CITY,
+               STATE,
+               ZIP,
+               COUNTRY,
+               PHONE,
+               WORKPHONE,
+               FAX,
+               MOBILEPHONE,
+               NICK,
+               URL,
+               NOTES,
+               CUSTOM1,
+               CUSTOM2,
+               CUSTOM3,
+               CUSTOM4,
+               CUSTOM5,
+               CSV_LAST
+       };
 
+       fprintf(out, "#");
+       fprintf(out, "\"NAME\",");
+       fprintf(out, "\"EMAIL\",");
+       fprintf(out, "\"ADDRESS\",");
+       fprintf(out, "\"ADDRESS2\",");
+       fprintf(out, "\"CITY\",");
+       fprintf(out, "\"STATE\",");
+       fprintf(out, "\"ZIP\",");
+       fprintf(out, "\"COUNTRY\",");
+       fprintf(out, "\"PHONE\",");
+       fprintf(out, "\"WORKPHONE\",");
+       fprintf(out, "\"FAX\",");
+       fprintf(out, "\"MOBILEPHONE\",");
+       fprintf(out, "\"NICK\",");
+       fprintf(out, "\"URL\",");
+       fprintf(out, "\"NOTES\",");
+       fprintf(out, "\"CUSTOM1\",");
+       fprintf(out, "\"CUSTOM2\",");
+       fprintf(out, "\"CUSTOM3\",");
+       fprintf(out, "\"CUSTOM4\",");
+       fprintf(out, "\"CUSTOM5\"\n");
+
+       csv_export_common(out, e, allcsv_export_fields, NULL);
+       
        return 0;
 }
 
 /*
- * end of csv export filter
+ * palm csv
  */
 
+#define PALM_CSV_NAME  CSV_SPECIAL(0)
+#define PALM_CSV_END   CSV_SPECIAL(1)
+#define PALM_CSV_CAT   CSV_SPECIAL(2)
+
+static void 
+palm_split_and_write_name(FILE *out, char *name)
+{
+       char *p;
+
+       assert(name);
+
+       if ( (p = strchr(name, ' ')) ) {
+               /*
+                * last name first
+                */
+               fprintf(out, "\"%s\",\"" , p + 1);
+               fwrite((void *)name, p - name, sizeof(char), out);
+               fputc('\"', out);
+       } else {
+               fprintf(out, "\"%s\"", safe_str(name));
+       }
+}
+
+static void 
+palm_csv_handle_specials(FILE *out, int item, int field)
+{
+       switch(field) {
+               case PALM_CSV_NAME:
+                       palm_split_and_write_name(out, database[item][NAME]);
+                       break;
+               case PALM_CSV_CAT:
+                       fprintf(out, "\"abook\"");
+                       break;
+               case PALM_CSV_END:
+                       fprintf(out, "\"0\"");
+                       break;
+               default:
+                       assert(0);
+       }
+}
+
+static int
+palm_export_database(FILE *out, struct db_enumerator e)
+{
+       int palm_export_fields[] = {
+               PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
+               CSV_UNDEFINED,          /* TITLE                */
+               CSV_UNDEFINED,          /* COMPANY              */
+               WORKPHONE,              /* WORK PHONE           */
+               PHONE,                  /* HOME PHONE           */
+               FAX,                    /* FAX                  */
+               MOBILEPHONE,            /* OTHER                */
+               EMAIL,                  /* EMAIL                */
+               ADDRESS,                /* ADDRESS              */ 
+               CITY,                   /* CITY                 */
+               STATE,                  /* STATE                */
+               ZIP,                    /* ZIP                  */
+               COUNTRY,                /* COUNTRY              */
+               NICK,                   /* DEFINED 1            */
+               URL,                    /* DEFINED 2            */
+               CSV_UNDEFINED,          /* DEFINED 3            */
+               CSV_UNDEFINED,          /* DEFINED 4            */
+               NOTES,                  /* NOTE                 */
+               PALM_CSV_END,           /* "0"                  */
+               PALM_CSV_CAT,           /* CATEGORY             */
+               CSV_LAST
+       };
+
+       csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
+
+       return 0;
+}
+
+/*
+ * end of csv export filters
+ */
 
 /*
  * GnomeCard (VCard) addressbook export filter
  */
 
 static int
-gcrd_export_database(FILE *out)
+gcrd_export_database(FILE *out, struct db_enumerator e)
 {
        char emails[MAX_EMAILS][MAX_EMAIL_LEN];
-       int i, j;
+       int j;
        char *name;
 
-       for(i=0; i < items; i++ ) {
+       db_enumerate_items(e) {
                fprintf(out, "BEGIN:VCARD\nFN:%s\n",
-                               safe_str(database[i][NAME]));
+                               safe_str(database[e.item][NAME]));
 
-               name = get_surname(database[i][NAME]);
-               for( j = strlen(database[i][NAME]) - 1; j >= 0; j-- ) {
-                       if(database[i][NAME][j] == ' ')
+               name = get_surname(database[e.item][NAME]);
+               for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
+                       if(database[e.item][NAME][j] == ' ')
                                break;
                } 
                fprintf(out, "N:%s;%.*s\n",
                        safe_str(name),
                        j,
-                       safe_str(database[i][NAME])
+                       safe_str(database[e.item][NAME])
                        ); 
 
                free(name);
 
-               if ( database[i][ADDRESS] )
-                       fprintf(out, "ADR:;;%s;%s;%s;%s;%s\n",
-                               safe_str(database[i][ADDRESS]),
-                               safe_str(database[i][CITY]),
-                               safe_str(database[i][STATE]),
-                               safe_str(database[i][ZIP]),
-                               safe_str(database[i][COUNTRY])
+               if ( database[e.item][ADDRESS] )
+                       fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
+                               safe_str(database[e.item][ADDRESS]),
+                               safe_str(database[e.item][ADDRESS2]),                           
+                               safe_str(database[e.item][CITY]),
+                               safe_str(database[e.item][STATE]),
+                               safe_str(database[e.item][ZIP]),
+                               safe_str(database[e.item][COUNTRY])
                                );
                
-               if (database[i][PHONE])
-                       fprintf(out, "TEL;HOME:%s\n", database[i][PHONE]);
-               if (database[i][WORKPHONE])
-                       fprintf(out, "TEL;WORK:%s\n", database[i][WORKPHONE]);
-               if (database[i][FAX])
-                       fprintf(out, "TEL;FAX:%s\n", database[i][FAX]);
-               if (database[i][MOBILEPHONE])
-                       fprintf(out, "TEL;CELL:%s\n", database[i][MOBILEPHONE]);
-
-               if ( database[i][EMAIL] ) {
-                       split_emailstr(i, emails);
+               if (database[e.item][PHONE])
+                       fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
+               if (database[e.item][WORKPHONE])
+                       fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
+               if (database[e.item][FAX])
+                       fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
+               if (database[e.item][MOBILEPHONE])
+                       fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
+
+               if ( database[e.item][EMAIL] ) {
+                       split_emailstr(e.item, emails);
                        for(j=0; j < MAX_EMAILS ; j++) {
                                if ( *emails[j] ) 
                                        fprintf(out, "EMAIL;INTERNET:%s\n",
@@ -1055,10 +1553,10 @@ gcrd_export_database(FILE *out)
                        }
                }
                
-               if ( database[i][NOTES] ) 
-                       fprintf(out, "NOTE:%s\n", database[i][NOTES]);
-               if (database[i][URL])
-                       fprintf(out, "URL:%s\n",  database[i][URL]);
+               if ( database[e.item][NOTES] ) 
+                       fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
+               if (database[e.item][URL])
+                       fprintf(out, "URL:%s\n",  database[e.item][URL]);
 
                fprintf(out, "END:VCARD\n\n");
                
@@ -1095,21 +1593,20 @@ mutt_alias_genalias(int i)
 }
 
 static int
-mutt_alias_export(FILE *out)
+mutt_alias_export(FILE *out, struct db_enumerator e)
 {
-       int i;
        char email[MAX_EMAIL_LEN];
        char *alias = NULL;
 
-       for(i=0; i<items; i++) {
-               alias = mutt_alias_genalias(i);
+       db_enumerate_items(e) {
+               alias = mutt_alias_genalias(e.item);
 
-               get_first_email(email, i);
+               get_first_email(email, e.item);
                fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
                                alias,
-                               database[i][NAME],
+                               database[e.item][NAME],
                                email);
-               my_free(alias);
+               xfree(alias);
        }
 
        return 0;
@@ -1124,13 +1621,78 @@ mutt_alias_export(FILE *out)
  * printable export filter
  */
 
+
+static void
+text_write_address_us(FILE *out, int i) {
+       fprintf(out, "\n%s", database[i][ADDRESS]);
+
+       if (database[i][ADDRESS2])
+               fprintf(out, "\n%s", database[i][ADDRESS2]);
+
+       if (database[i][CITY])
+               fprintf(out, "\n%s", database[i][CITY]);
+               
+       if (database[i][STATE] || database[i][ZIP]) {
+               fputc('\n', out);
+               
+               if(database[i][STATE]) {
+                       fprintf(out, "%s", database[i][STATE]);
+                       if(database[i][ZIP])
+                               fputc(' ', out);
+               }
+
+               if(database[i][ZIP])
+                       fprintf(out, "%s", database[i][ZIP]);
+       }
+
+       if (database[i][COUNTRY])
+               fprintf(out, "\n%s", database[i][COUNTRY]);
+}
+
+
+static void
+text_write_address_uk(FILE *out, int i) {
+       int j;
+
+       for (j = ADDRESS; j <= COUNTRY; j++)
+               if (database[i][j])
+                       fprintf(out, "\n%s", database[i][j]);
+}
+
+static void
+text_write_address_eu(FILE *out, int i) {
+       fprintf(out, "\n%s", database[i][ADDRESS]);
+
+       if (database[i][ADDRESS2])
+               fprintf(out, "\n%s", database[i][ADDRESS2]);
+
+       if (database[i][ZIP] || database[i][CITY]) {
+               fputc('\n', out);
+
+               if(database[i][ZIP]) {
+                       fprintf(out, "%s", database[i][ZIP]);
+                       if(database[i][CITY])
+                               fputc(' ', out);
+               }
+
+               if(database[i][CITY])
+                       fprintf(out, "%s", database[i][CITY]);
+       }
+       
+       if (database[i][STATE])
+               fprintf(out, "\n%s", database[i][STATE]);
+
+       if (database[i][COUNTRY])
+               fprintf(out, "\n%s", database[i][COUNTRY]);
+}
+
 static int
-text_export_database(FILE * out)
+text_export_database(FILE * out, struct db_enumerator e)
 {
        char emails[MAX_EMAILS][MAX_EMAIL_LEN];
-       int i, j;
+       int j;
        char *realname = get_real_name();
-       char *style = options_get_str("address_style");
+       char *style = opt_get_str(STR_ADDRESS_STYLE);
 
        fprintf(out,
                "-----------------------------------------\n%s's address book\n"
@@ -1138,76 +1700,49 @@ text_export_database(FILE * out)
                realname);
        free(realname);
 
-       for (i = 0; i < items; i++) {
+       db_enumerate_items(e) {
                fprintf(out,
                        "-----------------------------------------\n\n");
-               fprintf(out, "%s", database[i][NAME]);
-               if (database[i][NICK])
-                       fprintf(out, "\n(%s)", database[i][NICK]);
+               fprintf(out, "%s", database[e.item][NAME]);
+               if (database[e.item][NICK] && *database[e.item][NICK])
+                       fprintf(out, "\n(%s)", database[e.item][NICK]);
                fprintf(out, "\n");
 
-               if (*database[i][EMAIL]) {
+               if (*database[e.item][EMAIL]) {
                        fprintf(out, "\n");
-                       split_emailstr(i, emails);
+                       split_emailstr(e.item, emails);
                        for (j = 0; j < MAX_EMAILS; j++)
                                if (*emails[j])
                                        fprintf(out, "%s\n", emails[j]);
                }
                /* Print address */
-               if (database[i][ADDRESS]) {
-                       if (!safe_strcmp(style, "us")) {        /* US like */
-                               fprintf(out, "\n%s", database[i][ADDRESS]);
-                               if (database[i][CITY])
-                                       fprintf(out, "\n%s",
-                                               database[i][CITY]);
-                               if (database[i][STATE] || database[i][ZIP])
-                                       fprintf(out, "\n%s %s",
-                                               safe_str(database[i]
-                                                        [STATE]),
-                                               safe_str(database[i]
-                                                        [ZIP]));
-                               if (database[i][COUNTRY])
-                                       fprintf(out, "\n%s",
-                                               database[i][COUNTRY]);
-                       }
-
-                       else if (!safe_strcmp(style, "uk")) {   /* UK like */
-                               for (j = ADDRESS; j <= COUNTRY; j++)
-                                       if (database[i][j])
-                                               fprintf(out, "\n%s",
-                                                       database[i][j]);
-                       } else {        /* EU like */
-                               fprintf(out, "\n%s", database[i][ADDRESS]);
-                               if (database[i][ZIP] || database[i][CITY])
-                                       fprintf(out, "\n%s %s",
-                                               safe_str(database[i][ZIP]),
-                                               safe_str(database[i]
-                                                        [CITY]));
-                               if (database[i][STATE])
-                                       fprintf(out, "\n%s",
-                                               database[i][STATE]);
-                               if (database[i][COUNTRY])
-                                       fprintf(out, "\n%s",
-                                               database[i][COUNTRY]);
-                       }
+               if (database[e.item][ADDRESS]) {
+                       if (!safe_strcmp(style, "us"))  /* US like */
+                               text_write_address_us(out, e.item);
+                       else if (!safe_strcmp(style, "uk"))     /* UK like */
+                               text_write_address_uk(out, e.item);
+                       else    /* EU like */
+                               text_write_address_eu(out, e.item);
 
                        fprintf(out, "\n");
                }
 
-               if ((database[i][PHONE]) || (database[i][WORKPHONE]) ||
-                   (database[i][FAX]) || (database[i][MOBILEPHONE])) {
+               if ((database[e.item][PHONE]) ||
+                       (database[e.item][WORKPHONE]) ||
+                       (database[e.item][FAX]) ||
+                       (database[e.item][MOBILEPHONE])) {
                        fprintf(out, "\n");
                        for (j = PHONE; j <= MOBILEPHONE; j++)
-                               if (database[i][j])
+                               if (database[e.item][j])
                                        fprintf(out, "%s: %s\n",
                                                abook_fields[j].name,
-                                               database[i][j]);
+                                               database[e.item][j]);
                }
 
-               if (database[i][URL])
-                       fprintf(out, "\n%s\n", database[i][URL]);
-               if (database[i][NOTES])
-                       fprintf(out, "\n%s\n", database[i][NOTES]);
+               if (database[e.item][URL])
+                       fprintf(out, "\n%s\n", database[e.item][URL]);
+               if (database[e.item][NOTES])
+                       fprintf(out, "\n%s\n", database[e.item][NOTES]);
 
                fprintf(out, "\n");
        }
@@ -1226,20 +1761,19 @@ text_export_database(FILE * out)
  */
 
 static int
-elm_alias_export(FILE *out)
+elm_alias_export(FILE *out, struct db_enumerator e)
 {
-       int i;
        char email[MAX_EMAIL_LEN];
        char *alias = NULL;
 
-       for(i=0; i<items; i++) {
-               alias = mutt_alias_genalias(i);
-               get_first_email(email, i);
+       db_enumerate_items(e) {
+               alias = mutt_alias_genalias(e.item);
+               get_first_email(email, e.item);
                fprintf(out, "%s = %s = %s\n",
                                alias,
-                               database[i][NAME],
+                               database[e.item][NAME],
                                email);
-               my_free(alias);
+               xfree(alias);
        }
 
        return 0;
@@ -1255,21 +1789,20 @@ elm_alias_export(FILE *out)
  */
 
 static int
-spruce_export_database (FILE *out)
+spruce_export_database (FILE *out, struct db_enumerator e)
 {
-       int i;
        char email[MAX_EMAIL_LEN];
 
        fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
 
-       for (i= 0; i< items; i++) {
-               if(strcmp (safe_str(database[i][EMAIL]), "")) {
-                       get_first_email(email, i);
+       db_enumerate_items(e) {
+               if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
+                       get_first_email(email, e.item);
                        fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
-                                       i,
-                                       database[i][NAME],
+                                       e.item,
+                                       database[e.item][NAME],
                                        email,
-                                       safe_str(database[i][NOTES])
+                                       safe_str(database[e.item][NOTES])
                                        );
                }
        }