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