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