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