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