]> git.deb.at Git - pkg/abook.git/blob - filter.c
9ba0a18b23bc4a1ef0568a258b6cc9ee5874b3e8
[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 <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         int allcsv_export_fields[] = {
1364                 NAME,
1365                 EMAIL,
1366                 ADDRESS,
1367                 ADDRESS2,
1368                 CITY,
1369                 STATE,
1370                 ZIP,
1371                 COUNTRY,
1372                 PHONE,
1373                 WORKPHONE,
1374                 FAX,
1375                 MOBILEPHONE,
1376                 NICK,
1377                 URL,
1378                 NOTES,
1379                 CUSTOM1,
1380                 CUSTOM2,
1381                 CUSTOM3,
1382                 CUSTOM4,
1383                 CUSTOM5,
1384                 CSV_LAST
1385         };
1386
1387         fprintf(out, "#");
1388         fprintf(out, "\"NAME\",");
1389         fprintf(out, "\"EMAIL\",");
1390         fprintf(out, "\"ADDRESS\",");
1391         fprintf(out, "\"ADDRESS2\",");
1392         fprintf(out, "\"CITY\",");
1393         fprintf(out, "\"STATE\",");
1394         fprintf(out, "\"ZIP\",");
1395         fprintf(out, "\"COUNTRY\",");
1396         fprintf(out, "\"PHONE\",");
1397         fprintf(out, "\"WORKPHONE\",");
1398         fprintf(out, "\"FAX\",");
1399         fprintf(out, "\"MOBILEPHONE\",");
1400         fprintf(out, "\"NICK\",");
1401         fprintf(out, "\"URL\",");
1402         fprintf(out, "\"NOTES\",");
1403         fprintf(out, "\"CUSTOM1\",");
1404         fprintf(out, "\"CUSTOM2\",");
1405         fprintf(out, "\"CUSTOM3\",");
1406         fprintf(out, "\"CUSTOM4\",");
1407         fprintf(out, "\"CUSTOM5\"\n");
1408
1409         csv_export_common(out, e, allcsv_export_fields, NULL);
1410         
1411         return 0;
1412 }
1413
1414 /*
1415  * palm csv
1416  */
1417
1418 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1419 #define PALM_CSV_END    CSV_SPECIAL(1)
1420 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1421
1422 static void 
1423 palm_split_and_write_name(FILE *out, char *name)
1424 {
1425         char *p;
1426
1427         assert(name);
1428
1429         if ( (p = strchr(name, ' ')) ) {
1430                 /*
1431                  * last name first
1432                  */
1433                 fprintf(out, "\"%s\",\"" , p + 1);
1434                 fwrite((void *)name, p - name, sizeof(char), out);
1435                 fputc('\"', out);
1436         } else {
1437                 fprintf(out, "\"%s\"", safe_str(name));
1438         }
1439 }
1440
1441 static void 
1442 palm_csv_handle_specials(FILE *out, int item, int field)
1443 {
1444         switch(field) {
1445                 case PALM_CSV_NAME:
1446                         palm_split_and_write_name(out, database[item][NAME]);
1447                         break;
1448                 case PALM_CSV_CAT:
1449                         fprintf(out, "\"abook\"");
1450                         break;
1451                 case PALM_CSV_END:
1452                         fprintf(out, "\"0\"");
1453                         break;
1454                 default:
1455                         assert(0);
1456         }
1457 }
1458
1459 static int
1460 palm_export_database(FILE *out, struct db_enumerator e)
1461 {
1462         int palm_export_fields[] = {
1463                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1464                 CSV_UNDEFINED,          /* TITLE                */
1465                 CSV_UNDEFINED,          /* COMPANY              */
1466                 WORKPHONE,              /* WORK PHONE           */
1467                 PHONE,                  /* HOME PHONE           */
1468                 FAX,                    /* FAX                  */
1469                 MOBILEPHONE,            /* OTHER                */
1470                 EMAIL,                  /* EMAIL                */
1471                 ADDRESS,                /* ADDRESS              */ 
1472                 CITY,                   /* CITY                 */
1473                 STATE,                  /* STATE                */
1474                 ZIP,                    /* ZIP                  */
1475                 COUNTRY,                /* COUNTRY              */
1476                 NICK,                   /* DEFINED 1            */
1477                 URL,                    /* DEFINED 2            */
1478                 CSV_UNDEFINED,          /* DEFINED 3            */
1479                 CSV_UNDEFINED,          /* DEFINED 4            */
1480                 NOTES,                  /* NOTE                 */
1481                 PALM_CSV_END,           /* "0"                  */
1482                 PALM_CSV_CAT,           /* CATEGORY             */
1483                 CSV_LAST
1484         };
1485
1486         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1487
1488         return 0;
1489 }
1490
1491 /*
1492  * end of csv export filters
1493  */
1494
1495 /*
1496  * GnomeCard (VCard) addressbook export filter
1497  */
1498
1499 static int
1500 gcrd_export_database(FILE *out, struct db_enumerator e)
1501 {
1502         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1503         int j;
1504         char *name;
1505
1506         db_enumerate_items(e) {
1507                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1508                                 safe_str(database[e.item][NAME]));
1509
1510                 name = get_surname(database[e.item][NAME]);
1511                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1512                         if(database[e.item][NAME][j] == ' ')
1513                                 break;
1514                 } 
1515                 fprintf(out, "N:%s;%.*s\n",
1516                         safe_str(name),
1517                         j,
1518                         safe_str(database[e.item][NAME])
1519                         ); 
1520
1521                 free(name);
1522
1523                 if ( database[e.item][ADDRESS] )
1524                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1525                                 safe_str(database[e.item][ADDRESS]),
1526                                 safe_str(database[e.item][ADDRESS2]),                           
1527                                 safe_str(database[e.item][CITY]),
1528                                 safe_str(database[e.item][STATE]),
1529                                 safe_str(database[e.item][ZIP]),
1530                                 safe_str(database[e.item][COUNTRY])
1531                                 );
1532                 
1533                 if (database[e.item][PHONE])
1534                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1535                 if (database[e.item][WORKPHONE])
1536                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1537                 if (database[e.item][FAX])
1538                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1539                 if (database[e.item][MOBILEPHONE])
1540                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1541
1542                 if ( database[e.item][EMAIL] ) {
1543                         split_emailstr(e.item, emails);
1544                         for(j=0; j < MAX_EMAILS ; j++) {
1545                                 if ( *emails[j] ) 
1546                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1547                                                 emails[j]);
1548                         }
1549                 }
1550                 
1551                 if ( database[e.item][NOTES] ) 
1552                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1553                 if (database[e.item][URL])
1554                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1555
1556                 fprintf(out, "END:VCARD\n\n");
1557                 
1558         }
1559
1560         return 0;
1561 }
1562
1563 /*
1564  * end of GnomeCard export filter
1565  */
1566
1567
1568 /*
1569  * mutt alias export filter
1570  */
1571
1572 static char *
1573 mutt_alias_genalias(int i)
1574 {
1575         char *tmp, *pos;
1576         
1577         if(database[i][NICK])
1578                 return strdup(database[i][NICK]);
1579
1580         tmp = strdup(database[i][NAME]);
1581
1582         if( ( pos = strchr(tmp, ' ') ) )
1583                 *pos = 0;
1584
1585         strlower(tmp);
1586
1587         return tmp;     
1588 }
1589
1590 static int
1591 mutt_alias_export(FILE *out, struct db_enumerator e)
1592 {
1593         char email[MAX_EMAIL_LEN];
1594         char *alias = NULL;
1595
1596         db_enumerate_items(e) {
1597                 alias = mutt_alias_genalias(e.item);
1598
1599                 get_first_email(email, e.item);
1600                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1601                                 alias,
1602                                 database[e.item][NAME],
1603                                 email);
1604                 my_free(alias);
1605         }
1606
1607         return 0;
1608 }
1609
1610 /*
1611  * end of mutt alias export filter
1612  */
1613
1614
1615 /*
1616  * printable export filter
1617  */
1618
1619
1620 static void
1621 text_write_address_us(FILE *out, int i) {
1622         fprintf(out, "\n%s", database[i][ADDRESS]);
1623
1624         if (database[i][ADDRESS2])
1625                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1626
1627         if (database[i][CITY])
1628                 fprintf(out, "\n%s", database[i][CITY]);
1629                 
1630         if (database[i][STATE] || database[i][ZIP]) {
1631                 fputc('\n', out);
1632                 
1633                 if(database[i][STATE]) {
1634                         fprintf(out, "%s", database[i][STATE]);
1635                         if(database[i][ZIP])
1636                                 fputc(' ', out);
1637                 }
1638
1639                 if(database[i][ZIP])
1640                         fprintf(out, "%s", database[i][ZIP]);
1641         }
1642
1643         if (database[i][COUNTRY])
1644                 fprintf(out, "\n%s", database[i][COUNTRY]);
1645 }
1646
1647
1648 static void
1649 text_write_address_uk(FILE *out, int i) {
1650         int j;
1651
1652         for (j = ADDRESS; j <= COUNTRY; j++)
1653                 if (database[i][j])
1654                         fprintf(out, "\n%s", database[i][j]);
1655 }
1656
1657 static void
1658 text_write_address_eu(FILE *out, int i) {
1659         fprintf(out, "\n%s", database[i][ADDRESS]);
1660
1661         if (database[i][ADDRESS2])
1662                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1663
1664         if (database[i][ZIP] || database[i][CITY]) {
1665                 fputc('\n', out);
1666
1667                 if(database[i][ZIP]) {
1668                         fprintf(out, "%s", database[i][ZIP]);
1669                         if(database[i][CITY])
1670                                 fputc(' ', out);
1671                 }
1672
1673                 if(database[i][CITY])
1674                         fprintf(out, "%s", database[i][CITY]);
1675         }
1676         
1677         if (database[i][STATE])
1678                 fprintf(out, "\n%s", database[i][STATE]);
1679
1680         if (database[i][COUNTRY])
1681                 fprintf(out, "\n%s", database[i][COUNTRY]);
1682 }
1683
1684 static int
1685 text_export_database(FILE * out, struct db_enumerator e)
1686 {
1687         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1688         int j;
1689         char *realname = get_real_name();
1690         char *style = opt_get_str(STR_ADDRESS_STYLE);
1691
1692         fprintf(out,
1693                 "-----------------------------------------\n%s's address book\n"
1694                 "-----------------------------------------\n\n\n",
1695                 realname);
1696         free(realname);
1697
1698         db_enumerate_items(e) {
1699                 fprintf(out,
1700                         "-----------------------------------------\n\n");
1701                 fprintf(out, "%s", database[e.item][NAME]);
1702                 if (database[e.item][NICK] && *database[e.item][NICK])
1703                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1704                 fprintf(out, "\n");
1705
1706                 if (*database[e.item][EMAIL]) {
1707                         fprintf(out, "\n");
1708                         split_emailstr(e.item, emails);
1709                         for (j = 0; j < MAX_EMAILS; j++)
1710                                 if (*emails[j])
1711                                         fprintf(out, "%s\n", emails[j]);
1712                 }
1713                 /* Print address */
1714                 if (database[e.item][ADDRESS]) {
1715                         if (!safe_strcmp(style, "us"))  /* US like */
1716                                 text_write_address_us(out, e.item);
1717                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1718                                 text_write_address_uk(out, e.item);
1719                         else    /* EU like */
1720                                 text_write_address_eu(out, e.item);
1721
1722                         fprintf(out, "\n");
1723                 }
1724
1725                 if ((database[e.item][PHONE]) ||
1726                         (database[e.item][WORKPHONE]) ||
1727                         (database[e.item][FAX]) ||
1728                         (database[e.item][MOBILEPHONE])) {
1729                         fprintf(out, "\n");
1730                         for (j = PHONE; j <= MOBILEPHONE; j++)
1731                                 if (database[e.item][j])
1732                                         fprintf(out, "%s: %s\n",
1733                                                 abook_fields[j].name,
1734                                                 database[e.item][j]);
1735                 }
1736
1737                 if (database[e.item][URL])
1738                         fprintf(out, "\n%s\n", database[e.item][URL]);
1739                 if (database[e.item][NOTES])
1740                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1741
1742                 fprintf(out, "\n");
1743         }
1744
1745         fprintf(out, "-----------------------------------------\n");
1746
1747         return 0;
1748 }
1749
1750 /*
1751  * end of printable export filter
1752  */
1753
1754 /*
1755  * elm alias export filter
1756  */
1757
1758 static int
1759 elm_alias_export(FILE *out, struct db_enumerator e)
1760 {
1761         char email[MAX_EMAIL_LEN];
1762         char *alias = NULL;
1763
1764         db_enumerate_items(e) {
1765                 alias = mutt_alias_genalias(e.item);
1766                 get_first_email(email, e.item);
1767                 fprintf(out, "%s = %s = %s\n",
1768                                 alias,
1769                                 database[e.item][NAME],
1770                                 email);
1771                 my_free(alias);
1772         }
1773
1774         return 0;
1775 }
1776
1777 /*
1778  * end of elm alias export filter
1779  */
1780
1781
1782 /*
1783  * Spruce export filter
1784  */
1785
1786 static int
1787 spruce_export_database (FILE *out, struct db_enumerator e)
1788 {
1789         char email[MAX_EMAIL_LEN];
1790
1791         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1792
1793         db_enumerate_items(e) {
1794                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1795                         get_first_email(email, e.item);
1796                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1797                                         e.item,
1798                                         database[e.item][NAME],
1799                                         email,
1800                                         safe_str(database[e.item][NOTES])
1801                                         );
1802                 }
1803         }
1804
1805         fprintf (out, "# End of address book file.\n");
1806
1807         return 0;
1808 }
1809
1810 /*
1811  * end of Spruce export filter
1812  */
1813