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