]> git.deb.at Git - pkg/abook.git/blob - filter.c
new configuration system
[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 extern int extra_column;
787
788 static int
789 html_export_database(FILE *out, struct db_enumerator e)
790 {
791         char tmp[MAX_EMAILSTR_LEN];
792
793         if( items < 1 )
794                 return 2;
795
796         extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
797                 extra_column : PHONE;
798
799         html_export_write_head(out, extra_column);
800
801         db_enumerate_items(e) {
802                 get_first_email(tmp, e.item);
803                 if (*tmp)
804                     fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
805                             tmp,
806                             database[e.item][NAME] );
807                 else
808                     fprintf(out, "<tr>\n<td>%s\n",
809                             database[e.item][NAME] );
810
811                 fprintf(out, "<td>%s\n<td>%s\n",
812                                 database[e.item][EMAIL],
813                                 safe_str(database[e.item][extra_column]) );
814                 fprintf(out, "</tr>\n\n");
815         }
816
817         html_export_write_tail(out);
818
819         return 0;
820 }
821
822
823 static void
824 html_export_write_head(FILE *out, int extra_column)
825 {
826         char *realname = get_real_name();
827
828         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
829         fprintf(out, "<html>\n<head>\n <title>%s's addressbook</title>", realname );
830         fprintf(out, "\n</head>\n<body>\n");
831         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
832         fprintf(out, "<br><br>\n\n");
833
834         fprintf(out, "<table border=\"1\" align=\"center\">\n");
835         fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
836                         abook_fields[extra_column].name);
837
838         free(realname);
839 }
840
841 static void
842 html_export_write_tail(FILE *out)
843 {
844         fprintf(out, "\n</table>\n");
845         fprintf(out, "\n</body>\n</html>\n");
846 }
847         
848 /*
849  * end of html export filter
850  */
851
852
853 /*
854  * pine addressbook import filter
855  */
856
857 static void
858 pine_fixbuf(char *buf)
859 {
860         int i,j;
861
862         for(i=0,j=0; j < (int)strlen(buf); i++, j++)
863                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
864 }
865
866 static void
867 pine_convert_emails(char *s)
868 {
869         int i;
870         char *tmp;
871
872         if( s == NULL || *s != '(' )
873                 return;
874
875         for(i=0; s[i]; i++ )
876                 s[i] = s[i+1];
877
878         if( ( tmp = strchr(s,')')) )
879                 *tmp=0;
880         
881         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
882                 if( i > MAX_EMAILS - 1 ) {
883                         *tmp = 0;
884                         break;  
885                 }
886
887 }
888
889 static void
890 pine_parse_buf(char *buf)
891 {
892         list_item item;
893         char *start = buf;
894         char *end;
895         char tmp[400];
896         int i, len, last;
897         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
898
899         memset(&item, 0, sizeof(item) );
900         
901         for(i=0, last=0; !last ; i++) {
902                 if( ! (end = strchr(start, '\t')) )
903                         last=1;
904                 
905                 len = last ? strlen(start) : (int) (end-start);
906                 len = min(len, 400-1);
907         
908                 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
909                                 && pine_conv_table[i] >= 0) {
910                         strncpy(tmp, start, len);
911                         tmp[len] = 0;
912                         item[pine_conv_table[i]] = strdup(tmp);
913                 }
914                 start = end + 1;
915         }
916         
917         pine_convert_emails(item[EMAIL]);
918         add_item2database(item);
919 }
920                 
921
922 #define LINESIZE        1024
923
924 static int
925 pine_parse_file(FILE *in)
926 {
927         char line[LINESIZE];
928         char *buf = NULL;
929         char *ptr;
930         int i;
931
932         fgets(line, LINESIZE, in);      
933         
934         while(!feof(in)) {
935                 for(i = 2;;i++) {
936                         buf = (char *) realloc(buf, i*LINESIZE);
937                         if(i == 2)
938                                 strcpy(buf, line);
939                         fgets(line, LINESIZE, in);
940                         ptr=(char *)&line;
941                         if(*ptr != ' ' || feof(in) )
942                                 break;
943                         else
944                                 while( *ptr == ' ')
945                                         ptr++;
946                                 
947                         strcat(buf, ptr);
948                 }
949                 if( *buf == '#' ) {
950                         my_free(buf);
951                         continue;
952                 }
953                 pine_fixbuf(buf);
954
955                 pine_parse_buf(buf);
956
957                 my_free(buf);
958         }
959
960         return 0;
961 }
962
963 /*
964  * end of pine addressbook import filter
965  */
966
967
968 /*
969  * pine addressbook export filter
970  *
971  *  filter doesn't wrap the lines as it should but Pine seems to handle
972  *  created files without problems - JH
973  */
974
975 static int
976 pine_export_database(FILE *out, struct db_enumerator e)
977 {
978         db_enumerate_items(e) {
979                 fprintf(out, have_multiple_emails(e.item) ?
980                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
981                                 safe_str(database[e.item][NICK]),
982                                 safe_str(database[e.item][NAME]),
983                                 safe_str(database[e.item][EMAIL]),
984                                 safe_str(database[e.item][NOTES])
985                                 );
986         }
987
988         return 0;
989 }
990
991 /*
992  * end of pine addressbook export filter
993  */
994
995
996 /*
997  * csv import filter
998  */
999
1000 /* FIXME
1001  * these files should be parsed according to a certain
1002  * lay out, or the default if layout is not given, at 
1003  * the moment only default is done...
1004  */ 
1005
1006 #define CSV_COMMENT_CHAR        '#'
1007
1008 static int csv_conv_table[] = {
1009         NAME,
1010         EMAIL,
1011         PHONE,
1012         NOTES,
1013         NICK
1014 };
1015
1016 static void
1017 csv_convert_emails(char *s)
1018 {
1019         int i;
1020         char *tmp;
1021
1022         if( s == NULL )
1023                 return;
1024
1025         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1026                 if( i > MAX_EMAILS - 1 ) {
1027                         *tmp = 0;
1028                         break;  
1029                 }
1030
1031 }
1032
1033 static char *
1034 csv_remove_quotes(char *s)
1035 {
1036         char *copy, *trimmed;
1037         int len;
1038         
1039         copy = trimmed = strdup(s);
1040         strtrim(trimmed);
1041         
1042         len = strlen(trimmed);
1043         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1044                 if(len < 3) {
1045                         my_free(copy);
1046                         return NULL;
1047                 }
1048                 trimmed[len - 1] = 0;
1049                 trimmed++;
1050                 trimmed = strdup(trimmed);
1051                 free(copy);
1052                 return trimmed;
1053         }
1054
1055         my_free(copy);
1056         return strdup(s);
1057 }
1058
1059 static void
1060 csv_store_field(list_item item, char *s, int field)
1061 {
1062         char *newstr = NULL;
1063
1064         if(!s || !*s)
1065                 return;
1066
1067         if( !(newstr = csv_remove_quotes(s)) )
1068                 return;
1069
1070         if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1071                         && csv_conv_table[field] >= 0) {
1072                 item[csv_conv_table[field]] = newstr;
1073         } else {
1074                 my_free(newstr);
1075         }
1076 }
1077
1078 static int
1079 csv_is_valid_quote_end(char *p)
1080 {
1081         if(*p != '\"')
1082                 return FALSE;
1083
1084         for(p++; *p; p++) {
1085                 if(*p == ',')
1086                         return TRUE;
1087                 else if(!ISSPACE(*p))
1088                         return FALSE;
1089         }
1090
1091         return TRUE;
1092 }
1093
1094 static int
1095 csv_is_valid_quote_start(char *p)
1096 {
1097         for(; *p; p++) {
1098                 if(*p == '\"')
1099                         return TRUE;
1100                 else if(!ISSPACE(*p))
1101                         return FALSE;
1102         }
1103
1104         return FALSE;
1105 }
1106
1107 static void
1108 csv_parse_line(char *line)
1109 {
1110         char *p, *start;
1111         int field;
1112         bool in_quote = FALSE;
1113         list_item item;
1114
1115         memset(item, 0, sizeof(item));
1116
1117         for(p = start = line, field = 0; *p; p++) {
1118                 if(in_quote) {
1119                         if(csv_is_valid_quote_end(p))
1120                                 in_quote = FALSE;
1121                 } else {
1122                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1123                                 csv_is_valid_quote_start(p) )
1124                                 in_quote = TRUE;
1125                 }
1126
1127                 if( *p == ',' && !in_quote) {
1128                         *p = 0;
1129                         csv_store_field(item, start, field);
1130                         field++;
1131                         start = p + 1;
1132                 }
1133         }
1134         /*
1135          * store last field
1136          */
1137         csv_store_field(item, start, field);
1138
1139         csv_convert_emails(item[EMAIL]);
1140         add_item2database(item);
1141 }
1142
1143
1144 static int
1145 csv_parse_file(FILE *in)
1146 {
1147         char *line = NULL;
1148
1149         while(!feof(in)) {
1150                 line = getaline(in);
1151
1152                 if(line && *line && *line != CSV_COMMENT_CHAR)
1153                         csv_parse_line(line);
1154
1155                 my_free(line);
1156         }
1157
1158         return 0;
1159 }
1160
1161 /*
1162  * end of csv import filter
1163  */
1164
1165 /*
1166  * csv addressbook export filter
1167  */
1168
1169 static int
1170 csv_export_database(FILE *out, struct db_enumerator e)
1171 {
1172         int j;
1173         int csv_export_fields[] = {
1174                 NAME,
1175                 EMAIL,
1176                 PHONE,
1177                 NOTES,
1178                 NICK,
1179                 -1
1180         };
1181
1182         db_enumerate_items(e) {
1183                 for(j = 0; csv_export_fields[j] >= 0; j++) {
1184                         fprintf(out,(
1185                 strchr(safe_str(database[e.item][csv_export_fields[j]]), ',') ||
1186                 strchr(safe_str(database[e.item][csv_export_fields[j]]), '\"')
1187                         ) ?
1188                                 "\"%s\"" : "%s",
1189                                 safe_str(database[e.item][csv_export_fields[j]])
1190                                 );
1191                         if(csv_export_fields[j+1] >= 0)
1192                                 fputc(',', out);
1193                 }
1194                 fputc('\n', out);
1195         }
1196                 
1197
1198
1199         return 0;
1200 }
1201
1202 /*
1203  * end of csv export filter
1204  */
1205
1206
1207 /*
1208  * GnomeCard (VCard) addressbook export filter
1209  */
1210
1211 static int
1212 gcrd_export_database(FILE *out, struct db_enumerator e)
1213 {
1214         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1215         int j;
1216         char *name;
1217
1218         db_enumerate_items(e) {
1219                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1220                                 safe_str(database[e.item][NAME]));
1221
1222                 name = get_surname(database[e.item][NAME]);
1223                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1224                         if(database[e.item][NAME][j] == ' ')
1225                                 break;
1226                 } 
1227                 fprintf(out, "N:%s;%.*s\n",
1228                         safe_str(name),
1229                         j,
1230                         safe_str(database[e.item][NAME])
1231                         ); 
1232
1233                 free(name);
1234
1235                 if ( database[e.item][ADDRESS] )
1236                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1237                                 safe_str(database[e.item][ADDRESS]),
1238                                 safe_str(database[e.item][ADDRESS2]),                           
1239                                 safe_str(database[e.item][CITY]),
1240                                 safe_str(database[e.item][STATE]),
1241                                 safe_str(database[e.item][ZIP]),
1242                                 safe_str(database[e.item][COUNTRY])
1243                                 );
1244                 
1245                 if (database[e.item][PHONE])
1246                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1247                 if (database[e.item][WORKPHONE])
1248                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1249                 if (database[e.item][FAX])
1250                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1251                 if (database[e.item][MOBILEPHONE])
1252                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1253
1254                 if ( database[e.item][EMAIL] ) {
1255                         split_emailstr(e.item, emails);
1256                         for(j=0; j < MAX_EMAILS ; j++) {
1257                                 if ( *emails[j] ) 
1258                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1259                                                 emails[j]);
1260                         }
1261                 }
1262                 
1263                 if ( database[e.item][NOTES] ) 
1264                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1265                 if (database[e.item][URL])
1266                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1267
1268                 fprintf(out, "END:VCARD\n\n");
1269                 
1270         }
1271
1272         return 0;
1273 }
1274
1275 /*
1276  * end of GnomeCard export filter
1277  */
1278
1279
1280 /*
1281  * mutt alias export filter
1282  */
1283
1284 static char *
1285 mutt_alias_genalias(int i)
1286 {
1287         char *tmp, *pos;
1288         
1289         if(database[i][NICK])
1290                 return strdup(database[i][NICK]);
1291
1292         tmp = strdup(database[i][NAME]);
1293
1294         if( ( pos = strchr(tmp, ' ') ) )
1295                 *pos = 0;
1296
1297         strlower(tmp);
1298
1299         return tmp;     
1300 }
1301
1302 static int
1303 mutt_alias_export(FILE *out, struct db_enumerator e)
1304 {
1305         char email[MAX_EMAIL_LEN];
1306         char *alias = NULL;
1307
1308         db_enumerate_items(e) {
1309                 alias = mutt_alias_genalias(e.item);
1310
1311                 get_first_email(email, e.item);
1312                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1313                                 alias,
1314                                 database[e.item][NAME],
1315                                 email);
1316                 my_free(alias);
1317         }
1318
1319         return 0;
1320 }
1321
1322 /*
1323  * end of mutt alias export filter
1324  */
1325
1326
1327 /*
1328  * printable export filter
1329  */
1330
1331
1332 static void
1333 text_write_address_us(FILE *out, int i) {
1334         fprintf(out, "\n%s", database[i][ADDRESS]);
1335
1336         if (database[i][ADDRESS2])
1337                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1338
1339         if (database[i][CITY])
1340                 fprintf(out, "\n%s", database[i][CITY]);
1341                 
1342         if (database[i][STATE] || database[i][ZIP]) {
1343                 fputc('\n', out);
1344                 
1345                 if(database[i][STATE]) {
1346                         fprintf(out, "%s", database[i][STATE]);
1347                         if(database[i][ZIP])
1348                                 fputc(' ', out);
1349                 }
1350
1351                 if(database[i][ZIP])
1352                         fprintf(out, "%s", database[i][ZIP]);
1353         }
1354
1355         if (database[i][COUNTRY])
1356                 fprintf(out, "\n%s", database[i][COUNTRY]);
1357 }
1358
1359
1360 static void
1361 text_write_address_uk(FILE *out, int i) {
1362         int j;
1363
1364         for (j = ADDRESS; j <= COUNTRY; j++)
1365                 if (database[i][j])
1366                         fprintf(out, "\n%s", database[i][j]);
1367 }
1368
1369 static void
1370 text_write_address_eu(FILE *out, int i) {
1371         fprintf(out, "\n%s", database[i][ADDRESS]);
1372
1373         if (database[i][ADDRESS2])
1374                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1375
1376         if (database[i][ZIP] || database[i][CITY]) {
1377                 fputc('\n', out);
1378
1379                 if(database[i][ZIP]) {
1380                         fprintf(out, "%s", database[i][ZIP]);
1381                         if(database[i][CITY])
1382                                 fputc(' ', out);
1383                 }
1384
1385                 if(database[i][CITY])
1386                         fprintf(out, "%s", database[i][CITY]);
1387         }
1388         
1389         if (database[i][STATE])
1390                 fprintf(out, "\n%s", database[i][STATE]);
1391
1392         if (database[i][COUNTRY])
1393                 fprintf(out, "\n%s", database[i][COUNTRY]);
1394 }
1395
1396 static int
1397 text_export_database(FILE * out, struct db_enumerator e)
1398 {
1399         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1400         int j;
1401         char *realname = get_real_name();
1402         char *style = opt_get_str(STR_ADDRESS_STYLE);
1403
1404         fprintf(out,
1405                 "-----------------------------------------\n%s's address book\n"
1406                 "-----------------------------------------\n\n\n",
1407                 realname);
1408         free(realname);
1409
1410         db_enumerate_items(e) {
1411                 fprintf(out,
1412                         "-----------------------------------------\n\n");
1413                 fprintf(out, "%s", database[e.item][NAME]);
1414                 if (database[e.item][NICK])
1415                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1416                 fprintf(out, "\n");
1417
1418                 if (*database[e.item][EMAIL]) {
1419                         fprintf(out, "\n");
1420                         split_emailstr(e.item, emails);
1421                         for (j = 0; j < MAX_EMAILS; j++)
1422                                 if (*emails[j])
1423                                         fprintf(out, "%s\n", emails[j]);
1424                 }
1425                 /* Print address */
1426                 if (database[e.item][ADDRESS]) {
1427                         if (!safe_strcmp(style, "us"))  /* US like */
1428                                 text_write_address_us(out, e.item);
1429                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1430                                 text_write_address_uk(out, e.item);
1431                         else    /* EU like */
1432                                 text_write_address_eu(out, e.item);
1433
1434                         fprintf(out, "\n");
1435                 }
1436
1437                 if ((database[e.item][PHONE]) ||
1438                         (database[e.item][WORKPHONE]) ||
1439                         (database[e.item][FAX]) ||
1440                         (database[e.item][MOBILEPHONE])) {
1441                         fprintf(out, "\n");
1442                         for (j = PHONE; j <= MOBILEPHONE; j++)
1443                                 if (database[e.item][j])
1444                                         fprintf(out, "%s: %s\n",
1445                                                 abook_fields[j].name,
1446                                                 database[e.item][j]);
1447                 }
1448
1449                 if (database[e.item][URL])
1450                         fprintf(out, "\n%s\n", database[e.item][URL]);
1451                 if (database[e.item][NOTES])
1452                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1453
1454                 fprintf(out, "\n");
1455         }
1456
1457         fprintf(out, "-----------------------------------------\n");
1458
1459         return 0;
1460 }
1461
1462 /*
1463  * end of printable export filter
1464  */
1465
1466 /*
1467  * elm alias export filter
1468  */
1469
1470 static int
1471 elm_alias_export(FILE *out, struct db_enumerator e)
1472 {
1473         char email[MAX_EMAIL_LEN];
1474         char *alias = NULL;
1475
1476         db_enumerate_items(e) {
1477                 alias = mutt_alias_genalias(e.item);
1478                 get_first_email(email, e.item);
1479                 fprintf(out, "%s = %s = %s\n",
1480                                 alias,
1481                                 database[e.item][NAME],
1482                                 email);
1483                 my_free(alias);
1484         }
1485
1486         return 0;
1487 }
1488
1489 /*
1490  * end of elm alias export filter
1491  */
1492
1493
1494 /*
1495  * Spruce export filter
1496  */
1497
1498 static int
1499 spruce_export_database (FILE *out, struct db_enumerator e)
1500 {
1501         char email[MAX_EMAIL_LEN];
1502
1503         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1504
1505         db_enumerate_items(e) {
1506                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1507                         get_first_email(email, e.item);
1508                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1509                                         e.item,
1510                                         database[e.item][NAME],
1511                                         email,
1512                                         safe_str(database[e.item][NOTES])
1513                                         );
1514                 }
1515         }
1516
1517         fprintf (out, "# End of address book file.\n");
1518
1519         return 0;
1520 }
1521
1522 /*
1523  * end of Spruce export filter
1524  */
1525