]> git.deb.at Git - pkg/abook.git/blob - filter.c
- replace abook_malloc, abook_realloc and my_free with new xmalloc routines
[pkg/abook.git] / filter.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@users.sourceforge.net>
6  *
7  * Copyright (C) Jaakko Heinonen
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <pwd.h>
15 #include <sys/stat.h>
16 #include <sys/types.h>
17 #include "abook_curses.h"
18 #include "filter.h"
19 #include "abook.h"
20 #include "database.h"
21 #include "edit.h"
22 #include "list.h"
23 #include "misc.h"
24 #include "options.h"
25 #include "xmalloc.h"
26 #include <assert.h>
27
28 extern int items;
29 extern list_item *database;
30 extern struct abook_field abook_fields[];
31
32 /*
33  * function declarations
34  */
35
36 /*
37  * import filter prototypes
38  */
39
40 static int      ldif_parse_file(FILE *handle);
41 static int      mutt_parse_file(FILE *in);
42 static int      pine_parse_file(FILE *in);
43 static int      csv_parse_file(FILE *in);
44 static int      allcsv_parse_file(FILE *in);
45
46 /*
47  * export filter prototypes
48  */
49
50 static int      ldif_export_database(FILE *out, struct db_enumerator e);
51 static int      html_export_database(FILE *out, struct db_enumerator e);
52 static int      pine_export_database(FILE *out, struct db_enumerator e);
53 static int      csv_export_database(FILE *out, struct db_enumerator e);
54 static int      allcsv_export_database(FILE *out, struct db_enumerator e);
55 static int      palm_export_database(FILE *out, struct db_enumerator e);
56 static int      gcrd_export_database(FILE *out, struct db_enumerator e);
57 static int      mutt_alias_export(FILE *out, struct db_enumerator e);
58 static int      elm_alias_export(FILE *out, struct db_enumerator e);
59 static int      text_export_database(FILE *out, struct db_enumerator e);
60 static int      spruce_export_database(FILE *out, struct db_enumerator e);
61
62 /*
63  * end of function declarations
64  */
65
66 struct abook_input_filter i_filters[] = {
67         { "abook", "abook native format", parse_database },
68         { "ldif", "ldif / Netscape addressbook", ldif_parse_file },
69         { "mutt", "mutt alias", mutt_parse_file },
70         { "pine", "pine addressbook", pine_parse_file },
71         { "csv", "comma separated values", csv_parse_file },
72         { "allcsv", "comma separated all values", allcsv_parse_file },
73         { "\0", NULL, NULL }
74 };
75
76 struct abook_output_filter e_filters[] = {
77         { "abook", "abook native format", write_database },
78         { "ldif", "ldif / Netscape addressbook (.4ld)", ldif_export_database },
79         { "mutt", "mutt alias", mutt_alias_export },
80         { "html", "html document", html_export_database },
81         { "pine", "pine addressbook", pine_export_database },
82         { "gcrd", "GnomeCard (VCard) addressbook", gcrd_export_database },
83         { "csv", "comma separated values", csv_export_database },
84         { "allcsv", "comma separated all values", allcsv_export_database },
85         { "palmcsv", "Palm comma separated values", palm_export_database},
86         { "elm", "elm alias", elm_alias_export },
87         { "text", "plain text", text_export_database },
88         { "spruce", "Spruce address book", spruce_export_database },
89         { "\0", NULL, NULL }
90 };
91
92 /*
93  * common functions
94  */
95
96 void
97 print_filters()
98 {
99         int i;
100         
101         puts("input:");
102         for(i=0; *i_filters[i].filtname ; i++)
103                 printf("\t%s\t%s\n", i_filters[i].filtname,
104                         i_filters[i].desc);
105
106         putchar('\n');
107         
108         puts("output:");
109         for(i=0; *e_filters[i].filtname ; i++)
110                 printf("\t%s\t%s\n", e_filters[i].filtname,
111                         e_filters[i].desc);
112
113         putchar('\n');
114 }
115
116 static int
117 number_of_output_filters()
118 {
119         int i;
120
121         for(i=0; *e_filters[i].filtname ; i++)
122                 ;
123
124         return i;
125 }
126
127 static int
128 number_of_input_filters()
129 {
130         int i;
131
132         for(i=0; *i_filters[i].filtname ; i++)
133                 ;
134
135         return i;
136 }
137
138 static char *
139 get_real_name()
140 {
141         char *username = getenv("USER");
142         struct passwd *pwent;
143         int rtn;
144         char *tmp;
145
146         pwent = getpwnam(username);
147
148         if((tmp = strdup(pwent->pw_gecos)) == NULL)
149                 return strdup(username);
150
151         rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
152         if (rtn == EOF || rtn == 0) {
153                 free(tmp);
154                 return strdup(username);
155         } else
156                 return tmp;
157 }
158
159 /*
160  * import
161  */
162         
163 static int              i_read_file(char *filename, int (*func) (FILE *in));
164
165 static void
166 import_screen()
167 {
168         int i;
169         
170         clear();
171
172         refresh_statusline();
173         headerline("import database");
174
175         mvaddstr(3, 1, "please select a filter");
176         
177
178         for(i=0; *i_filters[i].filtname ; i++)
179                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
180                         i_filters[i].filtname,
181                         i_filters[i].desc);
182
183         mvprintw(6 + i, 6, "x -\tcancel");
184 }
185
186 int
187 import_database()
188 {
189         int filter;
190         char *filename;
191         int tmp = items;
192
193         import_screen();
194         
195         filter = getch() - 'a';
196         if(filter == 'x' - 'a' ||
197                 filter >= number_of_input_filters() || filter < 0) {
198                 refresh_screen();
199                 return 1;
200         }
201         
202         mvaddstr(5+filter, 2, "->");
203         
204         filename = ask_filename("Filename: ");
205         if( !filename ) {
206                 refresh_screen();
207                 return 2;
208         }
209                 
210         if(  i_read_file(filename, i_filters[filter].func ) )
211                 statusline_msg("Error occured while opening the file");
212         else if( tmp == items )
213                 statusline_msg("Hmm.., file seems not to be a valid file");
214         
215         refresh_screen();
216         free(filename);
217
218         return 0;
219 }
220
221
222
223 static int
224 i_read_file(char *filename, int (*func) (FILE *in))
225 {
226         FILE *in;
227         int ret = 0;
228
229         if( ( in = abook_fopen( filename, "r" ) ) == NULL )
230                 return 1;
231
232         ret = (*func) (in);
233
234         fclose(in);
235
236         return ret;     
237 }
238
239 int
240 import_file(char filtname[FILTNAME_LEN], char *filename)
241 {
242         int i;
243         int tmp = items;
244         int ret = 0;
245
246         for(i=0;; i++) {
247                 if( ! strncasecmp(i_filters[i].filtname, filtname,
248                                         FILTNAME_LEN) )
249                         break;
250                 if( ! *i_filters[i].filtname ) {
251                         i = -1;
252                         break;
253                 }
254         }
255
256         if( i<0 )
257                 return -1;
258
259         if( !strcmp(filename, "-") ) {
260                 struct stat s;
261                 if( (fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode))
262                         ret = 1;
263                 else
264                         ret = (*i_filters[i].func) (stdin);
265         } else
266                 ret =  i_read_file(filename, i_filters[i].func);
267         
268         if( tmp == items )
269                 ret = 1;
270         
271         return ret;
272 }
273
274 /*
275  * export
276  */
277
278 static int              e_write_file(char *filename,
279                 int (*func) (FILE *in, struct db_enumerator e), int mode);
280
281 static void
282 export_screen()
283 {
284         int i;
285         
286         clear();
287
288
289         refresh_statusline();
290         headerline("export database");
291
292         mvaddstr(3, 1, "please select a filter");
293         
294
295         for(i=0; *e_filters[i].filtname ; i++)
296                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
297                         e_filters[i].filtname,
298                         e_filters[i].desc);
299
300         mvprintw(6 + i, 6, "x -\tcancel");
301 }
302
303 int
304 export_database()
305 {
306         int filter;
307         int enum_mode = ENUM_ALL;
308         char *filename;
309
310         export_screen();
311         
312         filter = getch() - 'a';
313         if(filter == 'x' - 'a' ||
314                 filter >= number_of_output_filters() || filter < 0) {
315                 refresh_screen();
316                 return 1;
317         }
318         
319         mvaddstr(5+filter, 2, "->");
320
321         if( selected_items() ) {
322                 statusline_addstr("Export All/Selected/Cancel (A/s/c)");
323                 switch( tolower(getch()) ) {
324                         case 's':
325                                 enum_mode = ENUM_SELECTED;
326                                 break;
327                         case 'c':
328                                 clear_statusline();
329                                 return 1;
330                 }
331                 clear_statusline();
332         }
333         
334         filename = ask_filename("Filename: ");
335         if( !filename ) {
336                 refresh_screen();
337                 return 2;
338         }
339         
340         if(  e_write_file(filename, e_filters[filter].func, enum_mode ) )
341                 statusline_msg("Error occured while exporting");
342         
343         refresh_screen();
344         free(filename);
345
346         return 0;
347 }
348
349 static int
350 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
351                 int mode)
352 {
353         FILE *out;
354         int ret = 0;
355         struct db_enumerator enumerator = init_db_enumerator(mode);
356
357         if( (out = fopen(filename, "a")) == NULL )
358                 return 1;
359
360         if( ftell(out) )
361                 return 1;
362
363         ret = (*func) (out, enumerator);
364         
365         fclose(out);
366         
367         return ret;
368 }
369
370 int
371 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
372 {
373         int i;
374         struct db_enumerator e = init_db_enumerator(enum_mode);
375
376         for(i=0;; i++) {
377                 if( ! strncasecmp(e_filters[i].filtname, filtname,
378                                         FILTNAME_LEN) )
379                         break;
380                 if( ! *e_filters[i].filtname ) {
381                         i = -1;
382                         break;
383                 }
384         }
385
386         return (e_filters[i].func) (handle, e);
387 }
388
389
390
391 int
392 export_file(char filtname[FILTNAME_LEN], char *filename)
393 {
394         const int mode = ENUM_ALL;
395         int i;
396         int ret = 0;
397         struct db_enumerator e = init_db_enumerator(mode);
398         
399         for(i=0;; i++) {
400                 if( ! strncasecmp(e_filters[i].filtname, filtname,
401                                         FILTNAME_LEN) )
402                         break;
403                 if( ! *e_filters[i].filtname ) {
404                         i = -1;
405                         break;
406                 }
407         }
408
409         if( i<0 )
410                 return -1;
411
412         if( !strcmp(filename, "-") )
413                 ret = (e_filters[i].func) (stdout, e);
414         else
415                 ret =  e_write_file(filename, e_filters[i].func, mode);
416
417         return ret;
418 }
419
420 /*
421  * end of common functions
422  */
423
424 /*
425  * ldif import
426  */
427
428 #include "ldif.h"
429
430 static void     ldif_fix_string(char *str);
431
432 #define LDIF_ITEM_FIELDS        16
433
434 typedef char*  ldif_item[LDIF_ITEM_FIELDS];
435
436 static ldif_item ldif_field_names = {
437         "cn",   
438         "mail",
439         "streetaddress",
440         "streetaddress2",
441         "locality",
442         "st",
443         "postalcode",
444         "countryname",
445         "homephone",
446         "description",
447         "homeurl",
448         "facsimiletelephonenumber",
449         "cellphone",
450         "xmozillaanyphone",
451         "xmozillanickname",
452         "objectclass", /* this must be the last entry */
453 };
454
455 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
456         NAME,           /* "cn" */
457         EMAIL,          /* "mail" */
458         ADDRESS,        /* "streetaddress" */
459         ADDRESS2,       /* "streetaddress2" */     
460         CITY,           /* "locality" */
461         STATE,          /* "st" */
462         ZIP,            /* "postalcode" */
463         COUNTRY,        /* "countryname" */
464         PHONE,          /* "homephone" */
465         NOTES,          /* "description" */
466         URL,            /* "homeurl" */
467         FAX,            /* "facsimiletelephonenumber" */
468         MOBILEPHONE,    /* "cellphone" */
469         WORKPHONE,      /* "xmozillaanyphone" */
470         NICK,           /* "xmozillanickname" */
471         -1,             /* "objectclass" */ /* this must be the last entry */
472 };
473
474
475 static char * 
476 ldif_read_line(FILE *in)
477 {
478         char *buf = NULL;
479         char *ptr, *tmp;
480         long pos;
481         int i;
482
483         for(i = 1;;i++) {
484                 char *line;
485
486                 pos = ftell(in);
487                 line = getaline(in);
488                 
489                 if( feof(in) || !line )
490                         break;
491                 
492                 if(i == 1) {
493                         buf = line;
494                         continue;
495                 }
496
497                 if(*line != ' ') {
498                         fseek(in, pos, SEEK_SET); /* fixme ! */
499                         free(line);
500                         break;
501                 }
502
503                 ptr = line;
504                 while( *ptr == ' ')
505                         ptr++;
506
507                 tmp = buf;
508                 buf = strconcat(buf, ptr, NULL);
509                 free(tmp);
510                 free(line);
511         }
512
513         if(buf && *buf == '#' ) {
514                 free(buf);
515                 return NULL;
516         }
517
518         return buf;
519 }
520
521 static void
522 ldif_add_item(ldif_item ldif_item)
523 {
524         list_item abook_item;
525         int i;
526
527         memset(abook_item, 0, sizeof(abook_item));
528
529         if( !ldif_item[LDIF_ITEM_FIELDS -1] )
530                 goto bail_out;
531
532
533         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
534                 if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] )
535                         abook_item[ldif_conv_table[i]] = strdup(ldif_item[i]);
536         }
537
538         add_item2database(abook_item);
539
540 bail_out:
541         for(i=0; i < LDIF_ITEM_FIELDS; i++)
542                 xfree(ldif_item[i]);
543
544 }
545
546 static void
547 ldif_convert(ldif_item item, char *type, char *value)
548 {
549         int i;
550
551         if( !strcmp(type, "dn") ) {
552                 ldif_add_item(item);
553                 return;
554         }
555
556         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
557                 if( !safe_strcmp(ldif_field_names[i], type) && *value ) {
558                         if( i == LDIF_ITEM_FIELDS -1) /* this is a dirty hack */
559                                 if( safe_strcmp("person", value))
560                                         break;
561                         if(item[i])
562                                 xfree(item[i]);
563                         item[i] = strdup(value);
564                 }
565         }
566 }
567
568 static int
569 ldif_parse_file(FILE *handle)
570 {
571         char *line = NULL;
572         char *type, *value;
573         int vlen;
574         ldif_item item;
575
576         memset(item, 0, sizeof(item));
577
578         do {
579                 if( ! (line = ldif_read_line(handle)) )
580                         continue;
581
582                 if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) {
583                         xfree(line);
584                         continue; /* just skip the errors */
585                 }
586
587                 ldif_fix_string(value);
588
589                 ldif_convert(item, type, value);
590
591                 xfree(line);
592         } while ( !feof(handle) );
593
594         ldif_convert(item, "dn", "");
595
596         return 0;
597 }
598
599 static void
600 ldif_fix_string(char *str)
601 {
602         int i, j;
603
604         for( i = 0, j = 0; j < (int)strlen(str); i++, j++)
605                 str[i] = ( str[j] == (char)0xc3 ?
606                                 (char) str[++j] + (char) 0x40 :
607                                 str[j] );
608
609         str[i] = 0;
610 }
611
612 /*
613  * end of ldif import
614  */
615
616 /*
617  * mutt alias import filter
618  */
619
620 #include "getname.h"
621
622 static int
623 mutt_read_line(FILE *in, char **alias, char **rest)
624 {
625         char *line, *ptr, *tmp;
626         size_t alias_len;
627
628         if( !(line = ptr = getaline(in)) )
629                 return 1; /* error / EOF */
630
631         while( ISSPACE(*ptr) )
632                 ptr++;
633
634         if( strncmp("alias", ptr, 5) ) {
635                 free(line);
636                 return 1;
637         }
638
639         ptr += 5;
640
641         while( ISSPACE(*ptr) )
642                 ptr++;
643
644         tmp = ptr;
645
646         while( ! ISSPACE(*ptr) )
647                 ptr++;
648
649         /* includes also the trailing zero */
650         alias_len = (size_t)(ptr - tmp + 1);
651
652         if( (*alias = xmalloc(alias_len)) == NULL) {
653                 free(line);
654                 return 1;
655         }
656
657         strncpy(*alias, tmp, alias_len - 1);
658         *(*alias + alias_len - 1) = 0;
659
660         while(ISSPACE(*ptr))
661                 ptr++;
662
663         *rest = strdup(ptr);    
664
665         free(line);
666         return 0;
667 }
668
669 static void
670 mutt_fix_quoting(char *p)
671 {
672         char *escape = 0;
673
674         for(; *p; p++) {
675                 switch(*p) {
676                         case '\"':
677                                 if(escape)
678                                         *escape = ' ';
679                                 break;
680                         case '\\':
681                                 escape = p;
682                                 break;
683                         default:
684                                 escape = 0;
685                 }
686         }
687 }
688
689 static void
690 mutt_parse_email(list_item item)
691 {
692         char *line = item[NAME];
693         char *tmp;
694         char *name, *email;
695 #if 0
696         char *start = line;
697         int i = 0;
698 #endif
699
700         mutt_fix_quoting(line);
701         tmp = strconcat("From: ", line, NULL);
702         getname(tmp, &name, &email);
703         free(tmp);
704
705         if(name)
706                 item[NAME] = name;
707         else
708                 return;
709         if(email)
710                 item[EMAIL] = email;
711         else
712                 return;
713
714         /*
715          * this is completely broken
716          */
717 #if 0
718         while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
719                 tmp = strconcat("From: ", ++start, NULL);
720                 getname(tmp, &name, &email);
721                 free(tmp);
722                 free(name);
723                 if(email) {
724                         if(*email) {
725                                 tmp = strconcat(item[EMAIL], ",", email, NULL);
726                                 free(item[EMAIL]);
727                                 item[EMAIL] = tmp;
728                         } else {
729                                 xfree(email);
730                         }
731                 }
732         }
733 #endif
734 }
735
736 static int
737 mutt_parse_file(FILE *in)
738 {
739         list_item item;
740
741         for(;;) {
742                 memset(item, 0, sizeof(item));
743
744                 if( !mutt_read_line(in, &item[NICK],
745                                 &item[NAME]) )
746                         mutt_parse_email(item);
747
748                 if( feof(in) ) {
749                         free_list_item(item);
750                         break;
751                 }
752
753                 add_item2database(item);
754         }
755
756         return 0;
757 }
758
759 /*
760  * end of mutt alias import filter
761  */
762
763
764 /*
765  * ldif export filter
766  */
767
768 static void
769 ldif_fput_type_and_value(FILE *out,char *type, char *value )
770 {
771         char *tmp;
772
773         tmp = ldif_type_and_value(type, value, strlen(value));
774
775         fputs(tmp, out);
776
777         free(tmp);
778 }
779
780 static int
781 ldif_export_database(FILE *out, struct db_enumerator e)
782 {
783         char email[MAX_EMAILSTR_LEN];
784
785         fprintf(out, "version: 1\n");
786
787         db_enumerate_items(e) {
788                 char *tmp;
789                 int j;
790                 get_first_email(email, e.item);
791
792                 tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
793                 ldif_fput_type_and_value(out, "dn", tmp);
794                 free(tmp);
795
796                 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
797                         if(ldif_conv_table[j] >= 0) {
798                                 if(ldif_conv_table[j] == EMAIL)
799                                         ldif_fput_type_and_value(out,
800                                                 ldif_field_names[j], email);
801                                 else if(database[e.item][ldif_conv_table[j]])
802                                         ldif_fput_type_and_value(out,
803                                                 ldif_field_names[j],
804                                                 database[e.item][ldif_conv_table[j]]);
805                         }
806                 }
807
808                 fprintf(out, "objectclass: top\n"
809                                 "objectclass: person\n\n");
810         }
811
812         return 0;
813 }
814
815 /*
816  * end of ldif export filter
817  */
818
819 /*
820  * html export filter
821  */
822
823 static void            html_export_write_head(FILE *out, int extra_column);
824 static void            html_export_write_tail(FILE *out);
825
826 extern int extra_column;
827
828 static int
829 html_export_database(FILE *out, struct db_enumerator e)
830 {
831         char tmp[MAX_EMAILSTR_LEN];
832
833         if( items < 1 )
834                 return 2;
835
836         extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
837                 extra_column : PHONE;
838
839         html_export_write_head(out, extra_column);
840
841         db_enumerate_items(e) {
842                 get_first_email(tmp, e.item);
843                 if (*tmp)
844                     fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
845                             tmp,
846                             database[e.item][NAME] );
847                 else
848                     fprintf(out, "<tr>\n<td>%s\n",
849                             database[e.item][NAME] );
850
851                 fprintf(out, "<td>%s\n<td>%s\n",
852                                 database[e.item][EMAIL],
853                                 safe_str(database[e.item][extra_column]) );
854                 fprintf(out, "</tr>\n\n");
855         }
856
857         html_export_write_tail(out);
858
859         return 0;
860 }
861
862
863 static void
864 html_export_write_head(FILE *out, int extra_column)
865 {
866         char *realname = get_real_name();
867
868         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
869         fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>", realname );
870         fprintf(out, "\n</head>\n<body>\n");
871         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
872         fprintf(out, "<br><br>\n\n");
873
874         fprintf(out, "<table border=\"1\" align=\"center\">\n");
875         fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
876                         abook_fields[extra_column].name);
877
878         free(realname);
879 }
880
881 static void
882 html_export_write_tail(FILE *out)
883 {
884         fprintf(out, "\n</table>\n");
885         fprintf(out, "\n</body>\n</html>\n");
886 }
887         
888 /*
889  * end of html export filter
890  */
891
892
893 /*
894  * pine addressbook import filter
895  */
896
897 #define PINE_BUF_SIZE 2048
898
899 static void
900 pine_fixbuf(char *buf)
901 {
902         int i,j;
903
904         for(i=0,j=0; j < (int)strlen(buf); i++, j++)
905                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
906 }
907
908 static void
909 pine_convert_emails(char *s)
910 {
911         int i;
912         char *tmp;
913
914         if( s == NULL || *s != '(' )
915                 return;
916
917         for(i=0; s[i]; i++ )
918                 s[i] = s[i+1];
919
920         if( ( tmp = strchr(s,')')) )
921                 *tmp=0;
922
923         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
924                 if( i > MAX_EMAILS - 1 ) {
925                         *tmp = 0;
926                         break;  
927                 }
928
929 }
930
931 static void
932 pine_parse_buf(char *buf)
933 {
934         list_item item;
935         char *start = buf;
936         char *end;
937         char tmp[PINE_BUF_SIZE];
938         int i, len, last;
939         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
940
941         memset(&item, 0, sizeof(item));
942         
943         for(i=0, last=0; !last ; i++) {
944                 if( ! (end = strchr(start, '\t')) )
945                         last=1;
946
947                 len = last ? strlen(start) : (int) (end-start);
948                 len = min(len, PINE_BUF_SIZE - 1);
949
950                 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
951                                 && pine_conv_table[i] >= 0) {
952                         strncpy(tmp, start, len);
953                         tmp[len] = 0;
954                         if(*tmp)
955                                 item[pine_conv_table[i]] = strdup(tmp);
956                 }
957                 start = end + 1;
958         }
959
960         pine_convert_emails(item[EMAIL]);
961         add_item2database(item);
962 }
963
964
965 #define LINESIZE        1024
966
967 static int
968 pine_parse_file(FILE *in)
969 {
970         char line[LINESIZE];
971         char *buf = NULL;
972         char *ptr;
973         int i;
974
975         fgets(line, LINESIZE, in);      
976
977         while(!feof(in)) {
978                 for(i = 2;;i++) {
979                         buf = xrealloc(buf, i*LINESIZE);
980                         if(i == 2)
981                                 strcpy(buf, line);
982                         fgets(line, LINESIZE, in);
983                         ptr=(char *)&line;
984                         if(*ptr != ' ' || feof(in) )
985                                 break;
986                         else
987                                 while( *ptr == ' ')
988                                         ptr++;
989
990                         strcat(buf, ptr);
991                 }
992                 if( *buf == '#' ) {
993                         xfree(buf);
994                         continue;
995                 }
996                 pine_fixbuf(buf);
997
998                 pine_parse_buf(buf);
999
1000                 xfree(buf);
1001         }
1002
1003         return 0;
1004 }
1005
1006 /*
1007  * end of pine addressbook import filter
1008  */
1009
1010
1011 /*
1012  * pine addressbook export filter
1013  *
1014  *  filter doesn't wrap the lines as it should but Pine seems to handle
1015  *  created files without problems - JH
1016  */
1017
1018 static int
1019 pine_export_database(FILE *out, struct db_enumerator e)
1020 {
1021         db_enumerate_items(e) {
1022                 fprintf(out, have_multiple_emails(e.item) ?
1023                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1024                                 safe_str(database[e.item][NICK]),
1025                                 safe_str(database[e.item][NAME]),
1026                                 safe_str(database[e.item][EMAIL]),
1027                                 safe_str(database[e.item][NOTES])
1028                                 );
1029         }
1030
1031         return 0;
1032 }
1033
1034 /*
1035  * end of pine addressbook export filter
1036  */
1037
1038
1039 /*
1040  * csv import filter
1041  */
1042
1043 /* FIXME
1044  * these files should be parsed according to a certain
1045  * lay out, or the default if layout is not given, at 
1046  * the moment only default is done...
1047  */ 
1048
1049 #define CSV_COMMENT_CHAR        '#'
1050
1051 static int csv_conv_table[] = {
1052         NAME,
1053         EMAIL,
1054         PHONE,
1055         NOTES,
1056         NICK
1057 };
1058
1059 static int allcsv_conv_table[] = {
1060         NAME,
1061         EMAIL,
1062         ADDRESS,
1063         ADDRESS2,
1064         CITY,
1065         STATE,
1066         ZIP,
1067         COUNTRY,
1068         PHONE,
1069         WORKPHONE,
1070         FAX,
1071         MOBILEPHONE,
1072         NICK,
1073         URL,
1074         NOTES,
1075         CUSTOM1,
1076         CUSTOM2,
1077         CUSTOM3,
1078         CUSTOM4,
1079         CUSTOM5,
1080 };
1081
1082 static void
1083 csv_convert_emails(char *s)
1084 {
1085         int i;
1086         char *tmp;
1087
1088         if( s == NULL )
1089                 return;
1090
1091         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1092                 if( i > MAX_EMAILS - 1 ) {
1093                         *tmp = 0;
1094                         break;  
1095                 }
1096
1097 }
1098
1099 static char *
1100 csv_remove_quotes(char *s)
1101 {
1102         char *copy, *trimmed;
1103         int len;
1104
1105         copy = trimmed = strdup(s);
1106         strtrim(trimmed);
1107
1108         len = strlen(trimmed);
1109         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1110                 if(len < 3) {
1111                         xfree(copy);
1112                         return NULL;
1113                 }
1114                 trimmed[len - 1] = 0;
1115                 trimmed++;
1116                 trimmed = strdup(trimmed);
1117                 free(copy);
1118                 return trimmed;
1119         }
1120
1121         xfree(copy);
1122         return strdup(s);
1123 }
1124
1125 static void
1126 csv_store_field(list_item item, char *s, int field)
1127 {
1128         char *newstr = NULL;
1129
1130         if(!s || !*s)
1131                 return;
1132
1133         if( !(newstr = csv_remove_quotes(s)) )
1134                 return;
1135
1136         if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1137                         && csv_conv_table[field] >= 0) {
1138                 item[csv_conv_table[field]] = newstr;
1139         } else {
1140                 xfree(newstr);
1141         }
1142 }
1143
1144 static void
1145 allcsv_store_field(list_item item, char *s, int field)
1146 {
1147         char *newstr = NULL;
1148
1149         if(!s || !*s)
1150                 return;
1151
1152         if( !(newstr = csv_remove_quotes(s)) )
1153                 return;
1154
1155         if(field < (int)(sizeof(allcsv_conv_table) / sizeof(*allcsv_conv_table))
1156                         && allcsv_conv_table[field] >= 0) {
1157                 item[allcsv_conv_table[field]] = newstr;
1158         } else {
1159                 xfree(newstr);
1160         }
1161 }
1162
1163 static int
1164 csv_is_valid_quote_end(char *p)
1165 {
1166         if(*p != '\"')
1167                 return FALSE;
1168
1169         for(p++; *p; p++) {
1170                 if(*p == ',')
1171                         return TRUE;
1172                 else if(!ISSPACE(*p))
1173                         return FALSE;
1174         }
1175
1176         return TRUE;
1177 }
1178
1179 static int
1180 csv_is_valid_quote_start(char *p)
1181 {
1182         for(; *p; p++) {
1183                 if(*p == '\"')
1184                         return TRUE;
1185                 else if(!ISSPACE(*p))
1186                         return FALSE;
1187         }
1188
1189         return FALSE;
1190 }
1191
1192 static void
1193 csv_parse_line(char *line)
1194 {
1195         char *p, *start;
1196         int field;
1197         bool in_quote = FALSE;
1198         list_item item;
1199
1200         memset(item, 0, sizeof(item));
1201
1202         for(p = start = line, field = 0; *p; p++) {
1203                 if(in_quote) {
1204                         if(csv_is_valid_quote_end(p))
1205                                 in_quote = FALSE;
1206                 } else {
1207                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1208                                 csv_is_valid_quote_start(p) )
1209                                 in_quote = TRUE;
1210                 }
1211
1212                 if( *p == ',' && !in_quote) {
1213                         *p = 0;
1214                         csv_store_field(item, start, field);
1215                         field++;
1216                         start = p + 1;
1217                 }
1218         }
1219         /*
1220          * store last field
1221          */
1222         csv_store_field(item, start, field);
1223
1224         csv_convert_emails(item[EMAIL]);
1225         add_item2database(item);
1226 }
1227
1228 static void
1229 allcsv_parse_line(char *line)
1230 {
1231         char *p, *start;
1232         int field;
1233         bool in_quote = FALSE;
1234         list_item item;
1235
1236         memset(item, 0, sizeof(item));
1237
1238         for(p = start = line, field = 0; *p; p++) {
1239                 if(in_quote) {
1240                         if(csv_is_valid_quote_end(p))
1241                                 in_quote = FALSE;
1242                 } else {
1243                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1244                                 csv_is_valid_quote_start(p) )
1245                                 in_quote = TRUE;
1246                 }
1247
1248                 if( *p == ',' && !in_quote) {
1249                         *p = 0;
1250                         allcsv_store_field(item, start, field);
1251                         field++;
1252                         start = p + 1;
1253                 }
1254         }
1255         /*
1256          * store last field
1257          */
1258         allcsv_store_field(item, start, field);
1259
1260         csv_convert_emails(item[EMAIL]);
1261         add_item2database(item);
1262 }
1263
1264
1265 static int
1266 csv_parse_file(FILE *in)
1267 {
1268         char *line = NULL;
1269
1270         while(!feof(in)) {
1271                 line = getaline(in);
1272
1273                 if(line && *line && *line != CSV_COMMENT_CHAR)
1274                         csv_parse_line(line);
1275
1276                 xfree(line);
1277         }
1278
1279         return 0;
1280 }
1281
1282 static int
1283 allcsv_parse_file(FILE *in)
1284 {
1285         char *line = NULL;
1286
1287         while(!feof(in)) {
1288                 line = getaline(in);
1289
1290                 if(line && *line && *line != CSV_COMMENT_CHAR)
1291                         allcsv_parse_line(line);
1292
1293                 xfree(line);
1294         }
1295
1296         return 0;
1297 }
1298
1299 /*
1300  * end of csv import filter
1301  */
1302
1303 /*
1304  * csv addressbook export filters
1305  */
1306
1307 #define CSV_LAST                (-1)
1308 #define CSV_UNDEFINED           (-2)
1309 #define CSV_SPECIAL(X)          (-3 - (X))
1310 #define CSV_IS_SPECIAL(X)       ((X) <= -3)
1311
1312 static int
1313 csv_export_common(FILE *out, struct db_enumerator e,
1314                 int fields[], void (*special_func)(FILE *, int, int))
1315 {
1316         int i;
1317
1318         db_enumerate_items(e) {
1319                 for(i = 0; fields[i] != CSV_LAST; i++) {
1320                         if(fields[i] == CSV_UNDEFINED)
1321                                 fprintf(out, "\"\"");
1322                         else if(CSV_IS_SPECIAL(fields[i])) {
1323                                 if(special_func)
1324                                         (*special_func)(out, e.item, fields[i]);
1325                         } else
1326                                 /*fprintf(out,(
1327                         strchr(safe_str(database[e.item][fields[i]]), ',') ||
1328                         strchr(safe_str(database[e.item][fields[i]]), '\"')) ?
1329                                 "\"%s\"" : "%s",
1330                                 safe_str(database[e.item][fields[i]])
1331                                 );*/
1332                                 fprintf(out, "\"%s\"",
1333                                         safe_str(database[e.item][fields[i]]));
1334
1335                         if(fields[i + 1] != CSV_LAST)
1336                                 fputc(',', out);
1337                 }
1338                 fputc('\n', out);
1339         }
1340
1341         return 0;
1342 }
1343
1344 static int
1345 csv_export_database(FILE *out, struct db_enumerator e)
1346 {
1347         int csv_export_fields[] = {
1348                 NAME,
1349                 EMAIL,
1350                 PHONE,
1351                 NOTES,
1352                 NICK,
1353                 CSV_LAST
1354         };
1355
1356         csv_export_common(out, e, csv_export_fields, NULL);
1357         
1358         return 0;
1359 }
1360
1361 static int
1362 allcsv_export_database(FILE *out, struct db_enumerator e)
1363 {
1364         /*
1365          * TODO: Should get these atomatically from abook_fileds
1366          *  - JH
1367          */
1368         int allcsv_export_fields[] = {
1369                 NAME,
1370                 EMAIL,
1371                 ADDRESS,
1372                 ADDRESS2,
1373                 CITY,
1374                 STATE,
1375                 ZIP,
1376                 COUNTRY,
1377                 PHONE,
1378                 WORKPHONE,
1379                 FAX,
1380                 MOBILEPHONE,
1381                 NICK,
1382                 URL,
1383                 NOTES,
1384                 CUSTOM1,
1385                 CUSTOM2,
1386                 CUSTOM3,
1387                 CUSTOM4,
1388                 CUSTOM5,
1389                 CSV_LAST
1390         };
1391
1392         fprintf(out, "#");
1393         fprintf(out, "\"NAME\",");
1394         fprintf(out, "\"EMAIL\",");
1395         fprintf(out, "\"ADDRESS\",");
1396         fprintf(out, "\"ADDRESS2\",");
1397         fprintf(out, "\"CITY\",");
1398         fprintf(out, "\"STATE\",");
1399         fprintf(out, "\"ZIP\",");
1400         fprintf(out, "\"COUNTRY\",");
1401         fprintf(out, "\"PHONE\",");
1402         fprintf(out, "\"WORKPHONE\",");
1403         fprintf(out, "\"FAX\",");
1404         fprintf(out, "\"MOBILEPHONE\",");
1405         fprintf(out, "\"NICK\",");
1406         fprintf(out, "\"URL\",");
1407         fprintf(out, "\"NOTES\",");
1408         fprintf(out, "\"CUSTOM1\",");
1409         fprintf(out, "\"CUSTOM2\",");
1410         fprintf(out, "\"CUSTOM3\",");
1411         fprintf(out, "\"CUSTOM4\",");
1412         fprintf(out, "\"CUSTOM5\"\n");
1413
1414         csv_export_common(out, e, allcsv_export_fields, NULL);
1415         
1416         return 0;
1417 }
1418
1419 /*
1420  * palm csv
1421  */
1422
1423 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1424 #define PALM_CSV_END    CSV_SPECIAL(1)
1425 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1426
1427 static void 
1428 palm_split_and_write_name(FILE *out, char *name)
1429 {
1430         char *p;
1431
1432         assert(name);
1433
1434         if ( (p = strchr(name, ' ')) ) {
1435                 /*
1436                  * last name first
1437                  */
1438                 fprintf(out, "\"%s\",\"" , p + 1);
1439                 fwrite((void *)name, p - name, sizeof(char), out);
1440                 fputc('\"', out);
1441         } else {
1442                 fprintf(out, "\"%s\"", safe_str(name));
1443         }
1444 }
1445
1446 static void 
1447 palm_csv_handle_specials(FILE *out, int item, int field)
1448 {
1449         switch(field) {
1450                 case PALM_CSV_NAME:
1451                         palm_split_and_write_name(out, database[item][NAME]);
1452                         break;
1453                 case PALM_CSV_CAT:
1454                         fprintf(out, "\"abook\"");
1455                         break;
1456                 case PALM_CSV_END:
1457                         fprintf(out, "\"0\"");
1458                         break;
1459                 default:
1460                         assert(0);
1461         }
1462 }
1463
1464 static int
1465 palm_export_database(FILE *out, struct db_enumerator e)
1466 {
1467         int palm_export_fields[] = {
1468                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1469                 CSV_UNDEFINED,          /* TITLE                */
1470                 CSV_UNDEFINED,          /* COMPANY              */
1471                 WORKPHONE,              /* WORK PHONE           */
1472                 PHONE,                  /* HOME PHONE           */
1473                 FAX,                    /* FAX                  */
1474                 MOBILEPHONE,            /* OTHER                */
1475                 EMAIL,                  /* EMAIL                */
1476                 ADDRESS,                /* ADDRESS              */ 
1477                 CITY,                   /* CITY                 */
1478                 STATE,                  /* STATE                */
1479                 ZIP,                    /* ZIP                  */
1480                 COUNTRY,                /* COUNTRY              */
1481                 NICK,                   /* DEFINED 1            */
1482                 URL,                    /* DEFINED 2            */
1483                 CSV_UNDEFINED,          /* DEFINED 3            */
1484                 CSV_UNDEFINED,          /* DEFINED 4            */
1485                 NOTES,                  /* NOTE                 */
1486                 PALM_CSV_END,           /* "0"                  */
1487                 PALM_CSV_CAT,           /* CATEGORY             */
1488                 CSV_LAST
1489         };
1490
1491         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1492
1493         return 0;
1494 }
1495
1496 /*
1497  * end of csv export filters
1498  */
1499
1500 /*
1501  * GnomeCard (VCard) addressbook export filter
1502  */
1503
1504 static int
1505 gcrd_export_database(FILE *out, struct db_enumerator e)
1506 {
1507         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1508         int j;
1509         char *name;
1510
1511         db_enumerate_items(e) {
1512                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1513                                 safe_str(database[e.item][NAME]));
1514
1515                 name = get_surname(database[e.item][NAME]);
1516                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1517                         if(database[e.item][NAME][j] == ' ')
1518                                 break;
1519                 } 
1520                 fprintf(out, "N:%s;%.*s\n",
1521                         safe_str(name),
1522                         j,
1523                         safe_str(database[e.item][NAME])
1524                         ); 
1525
1526                 free(name);
1527
1528                 if ( database[e.item][ADDRESS] )
1529                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1530                                 safe_str(database[e.item][ADDRESS]),
1531                                 safe_str(database[e.item][ADDRESS2]),                           
1532                                 safe_str(database[e.item][CITY]),
1533                                 safe_str(database[e.item][STATE]),
1534                                 safe_str(database[e.item][ZIP]),
1535                                 safe_str(database[e.item][COUNTRY])
1536                                 );
1537                 
1538                 if (database[e.item][PHONE])
1539                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1540                 if (database[e.item][WORKPHONE])
1541                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1542                 if (database[e.item][FAX])
1543                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1544                 if (database[e.item][MOBILEPHONE])
1545                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1546
1547                 if ( database[e.item][EMAIL] ) {
1548                         split_emailstr(e.item, emails);
1549                         for(j=0; j < MAX_EMAILS ; j++) {
1550                                 if ( *emails[j] ) 
1551                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1552                                                 emails[j]);
1553                         }
1554                 }
1555                 
1556                 if ( database[e.item][NOTES] ) 
1557                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1558                 if (database[e.item][URL])
1559                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1560
1561                 fprintf(out, "END:VCARD\n\n");
1562                 
1563         }
1564
1565         return 0;
1566 }
1567
1568 /*
1569  * end of GnomeCard export filter
1570  */
1571
1572
1573 /*
1574  * mutt alias export filter
1575  */
1576
1577 static char *
1578 mutt_alias_genalias(int i)
1579 {
1580         char *tmp, *pos;
1581         
1582         if(database[i][NICK])
1583                 return strdup(database[i][NICK]);
1584
1585         tmp = strdup(database[i][NAME]);
1586
1587         if( ( pos = strchr(tmp, ' ') ) )
1588                 *pos = 0;
1589
1590         strlower(tmp);
1591
1592         return tmp;     
1593 }
1594
1595 static int
1596 mutt_alias_export(FILE *out, struct db_enumerator e)
1597 {
1598         char email[MAX_EMAIL_LEN];
1599         char *alias = NULL;
1600
1601         db_enumerate_items(e) {
1602                 alias = mutt_alias_genalias(e.item);
1603
1604                 get_first_email(email, e.item);
1605                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1606                                 alias,
1607                                 database[e.item][NAME],
1608                                 email);
1609                 xfree(alias);
1610         }
1611
1612         return 0;
1613 }
1614
1615 /*
1616  * end of mutt alias export filter
1617  */
1618
1619
1620 /*
1621  * printable export filter
1622  */
1623
1624
1625 static void
1626 text_write_address_us(FILE *out, int i) {
1627         fprintf(out, "\n%s", database[i][ADDRESS]);
1628
1629         if (database[i][ADDRESS2])
1630                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1631
1632         if (database[i][CITY])
1633                 fprintf(out, "\n%s", database[i][CITY]);
1634                 
1635         if (database[i][STATE] || database[i][ZIP]) {
1636                 fputc('\n', out);
1637                 
1638                 if(database[i][STATE]) {
1639                         fprintf(out, "%s", database[i][STATE]);
1640                         if(database[i][ZIP])
1641                                 fputc(' ', out);
1642                 }
1643
1644                 if(database[i][ZIP])
1645                         fprintf(out, "%s", database[i][ZIP]);
1646         }
1647
1648         if (database[i][COUNTRY])
1649                 fprintf(out, "\n%s", database[i][COUNTRY]);
1650 }
1651
1652
1653 static void
1654 text_write_address_uk(FILE *out, int i) {
1655         int j;
1656
1657         for (j = ADDRESS; j <= COUNTRY; j++)
1658                 if (database[i][j])
1659                         fprintf(out, "\n%s", database[i][j]);
1660 }
1661
1662 static void
1663 text_write_address_eu(FILE *out, int i) {
1664         fprintf(out, "\n%s", database[i][ADDRESS]);
1665
1666         if (database[i][ADDRESS2])
1667                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1668
1669         if (database[i][ZIP] || database[i][CITY]) {
1670                 fputc('\n', out);
1671
1672                 if(database[i][ZIP]) {
1673                         fprintf(out, "%s", database[i][ZIP]);
1674                         if(database[i][CITY])
1675                                 fputc(' ', out);
1676                 }
1677
1678                 if(database[i][CITY])
1679                         fprintf(out, "%s", database[i][CITY]);
1680         }
1681         
1682         if (database[i][STATE])
1683                 fprintf(out, "\n%s", database[i][STATE]);
1684
1685         if (database[i][COUNTRY])
1686                 fprintf(out, "\n%s", database[i][COUNTRY]);
1687 }
1688
1689 static int
1690 text_export_database(FILE * out, struct db_enumerator e)
1691 {
1692         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1693         int j;
1694         char *realname = get_real_name();
1695         char *style = opt_get_str(STR_ADDRESS_STYLE);
1696
1697         fprintf(out,
1698                 "-----------------------------------------\n%s's address book\n"
1699                 "-----------------------------------------\n\n\n",
1700                 realname);
1701         free(realname);
1702
1703         db_enumerate_items(e) {
1704                 fprintf(out,
1705                         "-----------------------------------------\n\n");
1706                 fprintf(out, "%s", database[e.item][NAME]);
1707                 if (database[e.item][NICK] && *database[e.item][NICK])
1708                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1709                 fprintf(out, "\n");
1710
1711                 if (*database[e.item][EMAIL]) {
1712                         fprintf(out, "\n");
1713                         split_emailstr(e.item, emails);
1714                         for (j = 0; j < MAX_EMAILS; j++)
1715                                 if (*emails[j])
1716                                         fprintf(out, "%s\n", emails[j]);
1717                 }
1718                 /* Print address */
1719                 if (database[e.item][ADDRESS]) {
1720                         if (!safe_strcmp(style, "us"))  /* US like */
1721                                 text_write_address_us(out, e.item);
1722                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1723                                 text_write_address_uk(out, e.item);
1724                         else    /* EU like */
1725                                 text_write_address_eu(out, e.item);
1726
1727                         fprintf(out, "\n");
1728                 }
1729
1730                 if ((database[e.item][PHONE]) ||
1731                         (database[e.item][WORKPHONE]) ||
1732                         (database[e.item][FAX]) ||
1733                         (database[e.item][MOBILEPHONE])) {
1734                         fprintf(out, "\n");
1735                         for (j = PHONE; j <= MOBILEPHONE; j++)
1736                                 if (database[e.item][j])
1737                                         fprintf(out, "%s: %s\n",
1738                                                 abook_fields[j].name,
1739                                                 database[e.item][j]);
1740                 }
1741
1742                 if (database[e.item][URL])
1743                         fprintf(out, "\n%s\n", database[e.item][URL]);
1744                 if (database[e.item][NOTES])
1745                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1746
1747                 fprintf(out, "\n");
1748         }
1749
1750         fprintf(out, "-----------------------------------------\n");
1751
1752         return 0;
1753 }
1754
1755 /*
1756  * end of printable export filter
1757  */
1758
1759 /*
1760  * elm alias export filter
1761  */
1762
1763 static int
1764 elm_alias_export(FILE *out, struct db_enumerator e)
1765 {
1766         char email[MAX_EMAIL_LEN];
1767         char *alias = NULL;
1768
1769         db_enumerate_items(e) {
1770                 alias = mutt_alias_genalias(e.item);
1771                 get_first_email(email, e.item);
1772                 fprintf(out, "%s = %s = %s\n",
1773                                 alias,
1774                                 database[e.item][NAME],
1775                                 email);
1776                 xfree(alias);
1777         }
1778
1779         return 0;
1780 }
1781
1782 /*
1783  * end of elm alias export filter
1784  */
1785
1786
1787 /*
1788  * Spruce export filter
1789  */
1790
1791 static int
1792 spruce_export_database (FILE *out, struct db_enumerator e)
1793 {
1794         char email[MAX_EMAIL_LEN];
1795
1796         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1797
1798         db_enumerate_items(e) {
1799                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1800                         get_first_email(email, e.item);
1801                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1802                                         e.item,
1803                                         database[e.item][NAME],
1804                                         email,
1805                                         safe_str(database[e.item][NOTES])
1806                                         );
1807                 }
1808         }
1809
1810         fprintf (out, "# End of address book file.\n");
1811
1812         return 0;
1813 }
1814
1815 /*
1816  * end of Spruce export filter
1817  */
1818