]> git.deb.at Git - pkg/abook.git/blob - filter.c
cleanups
[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 filters
1169  */
1170
1171 #define CSV_LAST                (-1)
1172 #define CSV_UNDEFINED           (-2)
1173 #define CSV_SPECIAL(X)          (-3 - (X))
1174 #define CSV_IS_SPECIAL(X)       ((X) <= -3)
1175
1176 static int
1177 csv_export_common(FILE *out, struct db_enumerator e,
1178                 int fields[], void (*special_func)(FILE *, int, int))
1179 {
1180         int i;
1181
1182         db_enumerate_items(e) {
1183                 for(i = 0; fields[i] != CSV_LAST; i++) {
1184                         if(fields[i] == CSV_UNDEFINED)
1185                                 fprintf(out, "\"\"");
1186                         else if(CSV_IS_SPECIAL(fields[i])) {
1187                                 if(special_func)
1188                                         (*special_func)(out, e.item, fields[i]);
1189                         } else
1190                                 /*fprintf(out,(
1191                         strchr(safe_str(database[e.item][fields[i]]), ',') ||
1192                         strchr(safe_str(database[e.item][fields[i]]), '\"')) ?
1193                                 "\"%s\"" : "%s",
1194                                 safe_str(database[e.item][fields[i]])
1195                                 );*/
1196                                 fprintf(out, "\"%s\"",
1197                                         safe_str(database[e.item][fields[i]]));
1198
1199                         if(fields[i + 1] != CSV_LAST)
1200                                 fputc(',', out);
1201                 }
1202                 fputc('\n', out);
1203         }
1204
1205         return 0;
1206 }
1207
1208 static int
1209 csv_export_database(FILE *out, struct db_enumerator e)
1210 {
1211         int csv_export_fields[] = {
1212                 NAME,
1213                 EMAIL,
1214                 PHONE,
1215                 NOTES,
1216                 NICK,
1217                 CSV_LAST
1218         };
1219
1220         csv_export_common(out, e, csv_export_fields, NULL);
1221         
1222         return 0;
1223 }
1224
1225 /*
1226  * palm csv
1227  */
1228
1229 #define PALM_CSV_NAME   CSV_SPECIAL(0)
1230 #define PALM_CSV_END    CSV_SPECIAL(1)
1231 #define PALM_CSV_CAT    CSV_SPECIAL(2)
1232
1233 static void 
1234 palm_split_and_write_name(FILE *out, char *name)
1235 {
1236         char *p;
1237
1238         assert(name);
1239
1240         if ( (p = strchr(name, ' ')) ) {
1241                 /*
1242                  * last name first
1243                  */
1244                 fprintf(out, "\"%s\",\"" , p + 1);
1245                 fwrite((void *)name, p - name, sizeof(char), out);
1246                 fputc('\"', out);
1247         } else {
1248                 fprintf(out, "\"%s\"", safe_str(name));
1249         }
1250 }
1251
1252 static void 
1253 palm_csv_handle_specials(FILE *out, int item, int field)
1254 {
1255         switch(field) {
1256                 case PALM_CSV_NAME:
1257                         palm_split_and_write_name(out, database[item][NAME]);
1258                         break;
1259                 case PALM_CSV_CAT:
1260                         fprintf(out, "\"abook\"");
1261                         break;
1262                 case PALM_CSV_END:
1263                         fprintf(out, "\"0\"");
1264                         break;
1265                 default:
1266                         assert(0);
1267         }
1268 }
1269
1270 static int
1271 palm_export_database(FILE *out, struct db_enumerator e)
1272 {
1273         int palm_export_fields[] = {
1274                 PALM_CSV_NAME,          /* LASTNAME, FIRSTNAME  */
1275                 CSV_UNDEFINED,          /* TITLE                */
1276                 CSV_UNDEFINED,          /* COMPANY              */
1277                 WORKPHONE,              /* WORK PHONE           */
1278                 PHONE,                  /* HOME PHONE           */
1279                 FAX,                    /* FAX                  */
1280                 MOBILEPHONE,            /* OTHER                */
1281                 EMAIL,                  /* EMAIL                */
1282                 ADDRESS,                /* ADDRESS              */ 
1283                 CITY,                   /* CITY                 */
1284                 STATE,                  /* STATE                */
1285                 ZIP,                    /* ZIP                  */
1286                 COUNTRY,                /* COUNTRY              */
1287                 NICK,                   /* DEFINED 1            */
1288                 URL,                    /* DEFINED 2            */
1289                 CSV_UNDEFINED,          /* DEFINED 3            */
1290                 CSV_UNDEFINED,          /* DEFINED 4            */
1291                 NOTES,                  /* NOTE                 */
1292                 PALM_CSV_END,           /* "0"                  */
1293                 PALM_CSV_CAT,           /* CATEGORY             */
1294                 CSV_LAST
1295         };
1296
1297         csv_export_common(out, e, palm_export_fields, palm_csv_handle_specials);
1298
1299         return 0;
1300 }
1301
1302 /*
1303  * end of csv export filters
1304  */
1305
1306 /*
1307  * GnomeCard (VCard) addressbook export filter
1308  */
1309
1310 static int
1311 gcrd_export_database(FILE *out, struct db_enumerator e)
1312 {
1313         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1314         int j;
1315         char *name;
1316
1317         db_enumerate_items(e) {
1318                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1319                                 safe_str(database[e.item][NAME]));
1320
1321                 name = get_surname(database[e.item][NAME]);
1322                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1323                         if(database[e.item][NAME][j] == ' ')
1324                                 break;
1325                 } 
1326                 fprintf(out, "N:%s;%.*s\n",
1327                         safe_str(name),
1328                         j,
1329                         safe_str(database[e.item][NAME])
1330                         ); 
1331
1332                 free(name);
1333
1334                 if ( database[e.item][ADDRESS] )
1335                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1336                                 safe_str(database[e.item][ADDRESS]),
1337                                 safe_str(database[e.item][ADDRESS2]),                           
1338                                 safe_str(database[e.item][CITY]),
1339                                 safe_str(database[e.item][STATE]),
1340                                 safe_str(database[e.item][ZIP]),
1341                                 safe_str(database[e.item][COUNTRY])
1342                                 );
1343                 
1344                 if (database[e.item][PHONE])
1345                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1346                 if (database[e.item][WORKPHONE])
1347                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1348                 if (database[e.item][FAX])
1349                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1350                 if (database[e.item][MOBILEPHONE])
1351                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1352
1353                 if ( database[e.item][EMAIL] ) {
1354                         split_emailstr(e.item, emails);
1355                         for(j=0; j < MAX_EMAILS ; j++) {
1356                                 if ( *emails[j] ) 
1357                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1358                                                 emails[j]);
1359                         }
1360                 }
1361                 
1362                 if ( database[e.item][NOTES] ) 
1363                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1364                 if (database[e.item][URL])
1365                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1366
1367                 fprintf(out, "END:VCARD\n\n");
1368                 
1369         }
1370
1371         return 0;
1372 }
1373
1374 /*
1375  * end of GnomeCard export filter
1376  */
1377
1378
1379 /*
1380  * mutt alias export filter
1381  */
1382
1383 static char *
1384 mutt_alias_genalias(int i)
1385 {
1386         char *tmp, *pos;
1387         
1388         if(database[i][NICK])
1389                 return strdup(database[i][NICK]);
1390
1391         tmp = strdup(database[i][NAME]);
1392
1393         if( ( pos = strchr(tmp, ' ') ) )
1394                 *pos = 0;
1395
1396         strlower(tmp);
1397
1398         return tmp;     
1399 }
1400
1401 static int
1402 mutt_alias_export(FILE *out, struct db_enumerator e)
1403 {
1404         char email[MAX_EMAIL_LEN];
1405         char *alias = NULL;
1406
1407         db_enumerate_items(e) {
1408                 alias = mutt_alias_genalias(e.item);
1409
1410                 get_first_email(email, e.item);
1411                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1412                                 alias,
1413                                 database[e.item][NAME],
1414                                 email);
1415                 my_free(alias);
1416         }
1417
1418         return 0;
1419 }
1420
1421 /*
1422  * end of mutt alias export filter
1423  */
1424
1425
1426 /*
1427  * printable export filter
1428  */
1429
1430
1431 static void
1432 text_write_address_us(FILE *out, int i) {
1433         fprintf(out, "\n%s", database[i][ADDRESS]);
1434
1435         if (database[i][ADDRESS2])
1436                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1437
1438         if (database[i][CITY])
1439                 fprintf(out, "\n%s", database[i][CITY]);
1440                 
1441         if (database[i][STATE] || database[i][ZIP]) {
1442                 fputc('\n', out);
1443                 
1444                 if(database[i][STATE]) {
1445                         fprintf(out, "%s", database[i][STATE]);
1446                         if(database[i][ZIP])
1447                                 fputc(' ', out);
1448                 }
1449
1450                 if(database[i][ZIP])
1451                         fprintf(out, "%s", database[i][ZIP]);
1452         }
1453
1454         if (database[i][COUNTRY])
1455                 fprintf(out, "\n%s", database[i][COUNTRY]);
1456 }
1457
1458
1459 static void
1460 text_write_address_uk(FILE *out, int i) {
1461         int j;
1462
1463         for (j = ADDRESS; j <= COUNTRY; j++)
1464                 if (database[i][j])
1465                         fprintf(out, "\n%s", database[i][j]);
1466 }
1467
1468 static void
1469 text_write_address_eu(FILE *out, int i) {
1470         fprintf(out, "\n%s", database[i][ADDRESS]);
1471
1472         if (database[i][ADDRESS2])
1473                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1474
1475         if (database[i][ZIP] || database[i][CITY]) {
1476                 fputc('\n', out);
1477
1478                 if(database[i][ZIP]) {
1479                         fprintf(out, "%s", database[i][ZIP]);
1480                         if(database[i][CITY])
1481                                 fputc(' ', out);
1482                 }
1483
1484                 if(database[i][CITY])
1485                         fprintf(out, "%s", database[i][CITY]);
1486         }
1487         
1488         if (database[i][STATE])
1489                 fprintf(out, "\n%s", database[i][STATE]);
1490
1491         if (database[i][COUNTRY])
1492                 fprintf(out, "\n%s", database[i][COUNTRY]);
1493 }
1494
1495 static int
1496 text_export_database(FILE * out, struct db_enumerator e)
1497 {
1498         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1499         int j;
1500         char *realname = get_real_name();
1501         char *style = opt_get_str(STR_ADDRESS_STYLE);
1502
1503         fprintf(out,
1504                 "-----------------------------------------\n%s's address book\n"
1505                 "-----------------------------------------\n\n\n",
1506                 realname);
1507         free(realname);
1508
1509         db_enumerate_items(e) {
1510                 fprintf(out,
1511                         "-----------------------------------------\n\n");
1512                 fprintf(out, "%s", database[e.item][NAME]);
1513                 if (database[e.item][NICK])
1514                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1515                 fprintf(out, "\n");
1516
1517                 if (*database[e.item][EMAIL]) {
1518                         fprintf(out, "\n");
1519                         split_emailstr(e.item, emails);
1520                         for (j = 0; j < MAX_EMAILS; j++)
1521                                 if (*emails[j])
1522                                         fprintf(out, "%s\n", emails[j]);
1523                 }
1524                 /* Print address */
1525                 if (database[e.item][ADDRESS]) {
1526                         if (!safe_strcmp(style, "us"))  /* US like */
1527                                 text_write_address_us(out, e.item);
1528                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1529                                 text_write_address_uk(out, e.item);
1530                         else    /* EU like */
1531                                 text_write_address_eu(out, e.item);
1532
1533                         fprintf(out, "\n");
1534                 }
1535
1536                 if ((database[e.item][PHONE]) ||
1537                         (database[e.item][WORKPHONE]) ||
1538                         (database[e.item][FAX]) ||
1539                         (database[e.item][MOBILEPHONE])) {
1540                         fprintf(out, "\n");
1541                         for (j = PHONE; j <= MOBILEPHONE; j++)
1542                                 if (database[e.item][j])
1543                                         fprintf(out, "%s: %s\n",
1544                                                 abook_fields[j].name,
1545                                                 database[e.item][j]);
1546                 }
1547
1548                 if (database[e.item][URL])
1549                         fprintf(out, "\n%s\n", database[e.item][URL]);
1550                 if (database[e.item][NOTES])
1551                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1552
1553                 fprintf(out, "\n");
1554         }
1555
1556         fprintf(out, "-----------------------------------------\n");
1557
1558         return 0;
1559 }
1560
1561 /*
1562  * end of printable export filter
1563  */
1564
1565 /*
1566  * elm alias export filter
1567  */
1568
1569 static int
1570 elm_alias_export(FILE *out, struct db_enumerator e)
1571 {
1572         char email[MAX_EMAIL_LEN];
1573         char *alias = NULL;
1574
1575         db_enumerate_items(e) {
1576                 alias = mutt_alias_genalias(e.item);
1577                 get_first_email(email, e.item);
1578                 fprintf(out, "%s = %s = %s\n",
1579                                 alias,
1580                                 database[e.item][NAME],
1581                                 email);
1582                 my_free(alias);
1583         }
1584
1585         return 0;
1586 }
1587
1588 /*
1589  * end of elm alias export filter
1590  */
1591
1592
1593 /*
1594  * Spruce export filter
1595  */
1596
1597 static int
1598 spruce_export_database (FILE *out, struct db_enumerator e)
1599 {
1600         char email[MAX_EMAIL_LEN];
1601
1602         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1603
1604         db_enumerate_items(e) {
1605                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1606                         get_first_email(email, e.item);
1607                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1608                                         e.item,
1609                                         database[e.item][NAME],
1610                                         email,
1611                                         safe_str(database[e.item][NOTES])
1612                                         );
1613                 }
1614         }
1615
1616         fprintf (out, "# End of address book file.\n");
1617
1618         return 0;
1619 }
1620
1621 /*
1622  * end of Spruce export filter
1623  */
1624