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