]> git.deb.at Git - pkg/abook.git/blob - filter.c
b4893983dfb40015bebf23c019c2d166dc653053
[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        16
419
420 typedef char*  ldif_item[LDIF_ITEM_FIELDS];
421
422 static ldif_item ldif_field_names = {
423         "cn",   
424         "mail",
425         "streetaddress",
426         "streetaddress2",
427         "locality",
428         "st",
429         "postalcode",
430         "countryname",
431         "homephone",
432         "description",
433         "homeurl",
434         "facsimiletelephonenumber",
435         "cellphone",
436         "xmozillaanyphone",
437         "xmozillanickname",
438         "objectclass", /* this must be the last entry */
439 };
440
441 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
442         NAME,           /* "cn" */
443         EMAIL,          /* "mail" */
444         ADDRESS,        /* "streetaddress" */
445         ADDRESS2,       /* "streetaddress2" */     
446         CITY,           /* "locality" */
447         STATE,          /* "st" */
448         ZIP,            /* "postalcode" */
449         COUNTRY,        /* "countryname" */
450         PHONE,          /* "homephone" */
451         NOTES,          /* "description" */
452         URL,            /* "homeurl" */
453         FAX,            /* "facsimiletelephonenumber" */
454         MOBILEPHONE,    /* "cellphone" */
455         WORKPHONE,      /* "xmozillaanyphone" */
456         NICK,           /* "xmozillanickname" */
457         -1,             /* "objectclass" */ /* this must be the last entry */
458 };
459
460
461 static char * 
462 ldif_read_line(FILE *in)
463 {
464         char *buf = NULL;
465         char *ptr, *tmp;
466         long pos;
467         int i;
468
469         for(i = 1;;i++) {
470                 char *line;
471
472                 pos = ftell(in);
473                 line = getaline(in);
474                 
475                 if( feof(in) || !line )
476                         break;
477                 
478                 if(i == 1) {
479                         buf = line;
480                         continue;
481                 }
482                 
483                 if(*line != ' ') {
484                         fseek(in, pos, SEEK_SET);
485                         free(line);
486                         break;
487                 }
488
489                 ptr = line;
490                 while( *ptr == ' ')
491                         ptr++;
492
493                 tmp = buf;
494                 buf = strconcat(buf, ptr, NULL);
495                 free(tmp);
496                 free(line);
497         }
498
499         if( *buf == '#' ) {
500                 free(buf);
501                 return NULL;
502         }
503                 
504         return buf;
505 }
506
507 static void
508 ldif_add_item(ldif_item ldif_item)
509 {
510         list_item abook_item;
511         int i;
512
513         memset(abook_item, 0, sizeof(abook_item));
514         
515         if( !ldif_item[LDIF_ITEM_FIELDS -1] )
516                 goto bail_out;
517         
518
519         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
520                 if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] )
521                         abook_item[ldif_conv_table[i]] = strdup(ldif_item[i]);
522         }
523
524         add_item2database(abook_item);
525
526 bail_out:
527         for(i=0; i < LDIF_ITEM_FIELDS; i++)
528                 my_free(ldif_item[i]);
529
530 }
531
532 static void
533 ldif_convert(ldif_item item, char *type, char *value)
534 {
535         int i;
536
537         if( !strcmp(type, "dn") ) {
538                 ldif_add_item(item);
539                 return;
540         }
541
542         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
543                 if( !safe_strcmp(ldif_field_names[i], type) && *value ) {
544                         if( i == LDIF_ITEM_FIELDS -1) /* this is a dirty hack */
545                                 if( safe_strcmp("person", value))
546                                         break;
547                         if(item[i])
548                                 my_free(item[i]);
549                         item[i] = strdup(value);
550                 }
551         }
552 }
553
554 static int
555 ldif_parse_file(FILE *handle)
556 {
557         char *line = NULL;
558         char *type, *value;
559         int vlen;
560         ldif_item item;
561
562         memset(item, 0, sizeof(item));
563
564         do {
565                 if( ! (line = ldif_read_line(handle)) )
566                         continue;
567
568                 if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) {
569                         my_free(line);
570                         continue; /* just skip the errors */
571                 }
572                                 
573                 ldif_fix_string(value);
574
575                 ldif_convert(item, type, value);
576
577                 my_free(line);
578         } while ( !feof(handle) );
579
580         ldif_convert(item, "dn", "");
581
582         return 0;
583 }
584
585 static void
586 ldif_fix_string(char *str)
587 {
588         int i, j;
589
590         for( i = 0, j = 0; j < strlen(str); i++, j++)
591                 str[i] = ( str[j] == (char)0xc3 ?
592                                 (char) str[++j] + (char) 0x40 :
593                                 str[j] );
594
595         str[i] = 0;
596 }
597
598 /*
599  * end of ldif import
600  */
601
602 /*
603  * mutt alias import filter
604  */
605
606 #include "getname.h"
607
608 static int
609 mutt_read_line(FILE *in, char **alias, char **rest)
610 {
611         char *line, *ptr, *tmp;
612
613         if( !(line = ptr = getaline(in)) )
614                 return 1; /* error / EOF */
615
616         while( ISSPACE(*ptr) )
617                 ptr++;
618
619         if( strncmp("alias", ptr, 5) ) {
620                 free(line);
621                 return 1;
622         }
623                 
624         ptr += 5;
625
626         while( ISSPACE(*ptr) )
627                 ptr++;
628
629         tmp = ptr;
630
631         while( ! ISSPACE(*ptr) )
632                 ptr++;
633
634         if( (*alias = (char *)malloc(ptr-tmp+1)) == NULL) {
635                 free(line);
636                 return 1;
637         }
638
639         strncpy(*alias, tmp, ptr-tmp);
640         *(*alias + (ptr - tmp)) = 0;
641
642         while( ISSPACE(*ptr) )
643                 ptr++;
644
645         *rest = strdup(ptr);    
646
647         free(line);
648         return 0;
649 }
650
651 static void
652 mutt_parse_email(list_item item)
653 {
654         char *line = item[NAME];
655         char *start = line, *tmp;
656         char *name, *email;
657         int i = 0;
658
659         tmp = strconcat("From: ", line, NULL);
660         getname(tmp, &name, &email);
661         free(tmp);
662
663         if(name)
664                 item[NAME] = name;
665         else
666                 return;
667         if(email)
668                 item[EMAIL] = email;
669         else
670                 return;
671         
672         while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
673                 tmp = strconcat("From: ", ++start, NULL);
674                 getname(tmp, &name, &email);
675                 free(tmp);
676                 free(name);
677                 if(email) {
678                         if(*email) {
679                                 tmp = strconcat(item[EMAIL], ",", email, NULL);
680                                 free(item[EMAIL]);
681                                 item[EMAIL] = tmp;
682                         } else {
683                                 my_free(email);
684                         }
685                 }
686         }
687 }
688
689 static int
690 mutt_parse_file(FILE *in)
691 {
692         list_item item;
693
694         for(;;) {
695                 memset(item, 0, sizeof(item));
696                 
697                 if( !mutt_read_line(in, &item[NICK],
698                                 &item[NAME]) )
699                         mutt_parse_email(item);
700
701                 if( feof(in) ) {
702                         free_list_item(item);
703                         break;
704                 }
705
706                 add_item2database(item);
707         }
708
709         return 0;
710 }
711
712 /*
713  * end of mutt alias import filter
714  */
715
716
717 /*
718  * ldif export filter
719  */
720
721 static void
722 ldif_fput_type_and_value(FILE *out,char *type, char *value )
723 {
724         char *tmp;
725
726         tmp = ldif_type_and_value(type, value, strlen(value));
727
728         fputs(tmp, out);
729
730         free(tmp);
731 }
732
733 static int
734 ldif_export_database(FILE *out, struct db_enumerator e)
735 {
736         char email[MAX_EMAILSTR_LEN];
737
738         fprintf(out, "version: 1\n");
739
740         db_enumerate_items(e) {
741                 char *tmp;
742                 int j;
743                 get_first_email(email, e.item);
744
745                 tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
746                 ldif_fput_type_and_value(out, "dn", tmp);
747                 free(tmp);
748
749                 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
750                         if(ldif_conv_table[j] >= 0) {
751                                 if(ldif_conv_table[j] == EMAIL)
752                                         ldif_fput_type_and_value(out,
753                                                 ldif_field_names[j], email);
754                                 else if(database[e.item][ldif_conv_table[j]])
755                                         ldif_fput_type_and_value(out,
756                                                 ldif_field_names[j],
757                                                 database[e.item][ldif_conv_table[j]]);
758                         }
759                 }
760
761                 fprintf(out, "objectclass: top\n"
762                                 "objectclass: person\n\n");
763         }
764
765         return 0;
766 }
767
768 /*
769  * end of ldif export filter
770  */
771
772 /*
773  * html export filter
774  */
775
776 static void            html_export_write_head(FILE *out, int extra_column);
777 static void            html_export_write_tail(FILE *out);
778
779 static int
780 html_export_database(FILE *out, struct db_enumerator e)
781 {
782         char tmp[MAX_EMAILSTR_LEN];
783         int extra_column = options_get_int("extra_column");
784
785         if( items < 1 )
786                 return 2;
787
788         extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
789                 extra_column : PHONE;
790
791         html_export_write_head(out, extra_column);
792
793         db_enumerate_items(e) {
794                 get_first_email(tmp, e.item);
795                 if (*tmp)
796                     fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
797                             tmp,
798                             database[e.item][NAME] );
799                 else
800                     fprintf(out, "<tr>\n<td>%s\n",
801                             database[e.item][NAME] );
802
803                 fprintf(out, "<td>%s\n<td>%s\n",
804                                 database[e.item][EMAIL],
805                                 safe_str(database[e.item][extra_column]) );
806                 fprintf(out, "</tr>\n\n");
807         }
808
809         html_export_write_tail(out);
810
811         return 0;
812 }
813
814
815 static void
816 html_export_write_head(FILE *out, int extra_column)
817 {
818         char *realname = get_real_name();
819
820         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
821         fprintf(out, "<html>\n<head>\n  <title>%s's addressbook</title>",
822                         realname );
823         fprintf(out, "\n</head>\n<body>\n");
824         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
825         fprintf(out, "<br><br>\n\n");
826
827         fprintf(out, "<center><table border>\n");
828         fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
829                         abook_fields[extra_column].name);
830
831         free(realname);
832 }
833
834 static void
835 html_export_write_tail(FILE *out)
836 {
837         fprintf(out, "\n</table></center>\n");
838         fprintf(out, "\n</body>\n</html>\n");
839 }
840         
841 /*
842  * end of html export filter
843  */
844
845
846 /*
847  * pine addressbook import filter
848  */
849
850 static void
851 pine_fixbuf(char *buf)
852 {
853         int i,j;
854
855         for(i=0,j=0; j < strlen(buf); i++, j++)
856                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
857 }
858
859 static void
860 pine_convert_emails(char *s)
861 {
862         int i;
863         char *tmp;
864
865         if( s == NULL || *s != '(' )
866                 return;
867
868         for(i=0; s[i]; i++ )
869                 s[i] = s[i+1];
870
871         if( ( tmp = strchr(s,')')) )
872                 *tmp=0;
873         
874         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
875                 if( i > MAX_EMAILS - 1 ) {
876                         *tmp = 0;
877                         break;  
878                 }
879
880 }
881
882 static void
883 pine_parse_buf(char *buf)
884 {
885         list_item item;
886         char *start = buf;
887         char *end;
888         char tmp[400];
889         int i, len, last;
890         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
891
892         memset(&item, 0, sizeof(item) );
893         
894         for(i=0, last=0; !last ; i++) {
895                 if( ! (end = strchr(start, '\t')) )
896                         last=1;
897                 
898                 len = last ? strlen(start) : (int) (end-start);
899                 len = min(len, 400-1);
900         
901                 if(i < sizeof(pine_conv_table) / sizeof(*pine_conv_table)
902                                 && pine_conv_table[i] >= 0) {
903                         strncpy(tmp, start, len);
904                         tmp[len] = 0;
905                         item[pine_conv_table[i]] = strdup(tmp);
906                 }
907                 start = end + 1;
908         }
909         
910         pine_convert_emails(item[EMAIL]);
911         add_item2database(item);
912 }
913                 
914
915 #define LINESIZE        1024
916
917 static int
918 pine_parse_file(FILE *in)
919 {
920         char line[LINESIZE];
921         char *buf = NULL;
922         char *ptr;
923         int i;
924
925         fgets(line, LINESIZE, in);      
926         
927         while(!feof(in)) {
928                 for(i = 2;;i++) {
929                         buf = (char *) realloc(buf, i*LINESIZE);
930                         if(i == 2)
931                                 strcpy(buf, line);
932                         fgets(line, LINESIZE, in);
933                         ptr=(char *)&line;
934                         if(*ptr != ' ' || feof(in) )
935                                 break;
936                         else
937                                 while( *ptr == ' ')
938                                         ptr++;
939                                 
940                         strcat(buf, ptr);
941                 }
942                 if( *buf == '#' ) {
943                         my_free(buf);
944                         continue;
945                 }
946                 pine_fixbuf(buf);
947
948                 pine_parse_buf(buf);
949
950                 my_free(buf);
951         }
952
953         return 0;
954 }
955
956 /*
957  * end of pine addressbook import filter
958  */
959
960
961 /*
962  * pine addressbook export filter
963  *
964  *  filter doesn't wrap the lines as it should but Pine seems to handle
965  *  created files without problems - JH
966  */
967
968 static int
969 pine_export_database(FILE *out, struct db_enumerator e)
970 {
971         db_enumerate_items(e) {
972                 fprintf(out, have_multiple_emails(e.item) ?
973                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
974                                 safe_str(database[e.item][NICK]),
975                                 safe_str(database[e.item][NAME]),
976                                 safe_str(database[e.item][EMAIL]),
977                                 safe_str(database[e.item][NOTES])
978                                 );
979         }
980
981         return 0;
982 }
983
984 /*
985  * end of pine addressbook export filter
986  */
987
988
989 /*
990  * csv import filter
991  */
992
993 /* FIXME
994  * these files should be parsed according to a certain
995  * lay out, or the default if layout is not given, at 
996  * the moment only default is done...
997  */ 
998
999 #define CSV_COMMENT_CHAR        '#'
1000
1001 static int csv_conv_table[] = {
1002         NAME,
1003         EMAIL,
1004         PHONE,
1005         NOTES,
1006         NICK
1007 };
1008
1009 static void
1010 csv_convert_emails(char *s)
1011 {
1012         int i;
1013         char *tmp;
1014
1015         if( s == NULL )
1016                 return;
1017
1018         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1019                 if( i > MAX_EMAILS - 1 ) {
1020                         *tmp = 0;
1021                         break;  
1022                 }
1023
1024 }
1025
1026 static char *
1027 csv_remove_quotes(char *s)
1028 {
1029         char *copy, *trimmed;
1030         int len;
1031         
1032         copy = trimmed = strdup(s);
1033         strtrim(trimmed);
1034         
1035         len = strlen(trimmed);
1036         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1037                 if(len < 3) {
1038                         my_free(copy);
1039                         return NULL;
1040                 }
1041                 trimmed[len - 1] = 0;
1042                 trimmed++;
1043                 trimmed = strdup(trimmed);
1044                 free(copy);
1045                 return trimmed;
1046         }
1047
1048         my_free(copy);
1049         return strdup(s);
1050 }
1051
1052 static void
1053 csv_store_field(list_item item, char *s, int field)
1054 {
1055         char *newstr = NULL;
1056
1057         if(!s || !*s)
1058                 return;
1059
1060         if( !(newstr = csv_remove_quotes(s)) )
1061                 return;
1062
1063         if(field < (sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1064                         && csv_conv_table[field] >= 0) {
1065                 item[csv_conv_table[field]] = newstr;
1066         }
1067 }
1068
1069 static int
1070 csv_is_valid_quote_end(char *p)
1071 {
1072         if(*p != '\"')
1073                 return FALSE;
1074
1075         for(p++; *p; p++) {
1076                 if(*p == ',')
1077                         return TRUE;
1078                 else if(!ISSPACE(*p))
1079                         return FALSE;
1080         }
1081
1082         return TRUE;
1083 }
1084
1085 static int
1086 csv_is_valid_quote_start(char *p)
1087 {
1088         for(; *p; p++) {
1089                 if(*p == '\"')
1090                         return TRUE;
1091                 else if(!ISSPACE(*p))
1092                         return FALSE;
1093         }
1094
1095         return FALSE;
1096 }
1097
1098 static void
1099 csv_parse_line(char *line)
1100 {
1101         char *p, *start;
1102         int field;
1103         int in_quote = FALSE;
1104         list_item item;
1105
1106         memset(item, 0, sizeof(item));
1107
1108         for(p = start = line, field = 0; *p; p++) {
1109                 if(in_quote) {
1110                         if(csv_is_valid_quote_end(p))
1111                                 in_quote = FALSE;
1112                 } else {
1113                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1114                                 csv_is_valid_quote_start(p) )
1115                                 in_quote = TRUE;
1116                 }
1117
1118                 if( *p == ',' && !in_quote) {
1119                         *p = 0;
1120                         csv_store_field(item, start, field);
1121                         field++;
1122                         start = p + 1;
1123                 }
1124         }
1125         /*
1126          * store last field
1127          */
1128         csv_store_field(item, start, field);
1129
1130         csv_convert_emails(item[EMAIL]);
1131         add_item2database(item);
1132 }
1133
1134
1135 static int
1136 csv_parse_file(FILE *in)
1137 {
1138         char *line = NULL;
1139
1140         while(!feof(in)) {
1141                 line = getaline(in);
1142
1143                 if(line && *line && *line != CSV_COMMENT_CHAR)
1144                         csv_parse_line(line);
1145
1146                 my_free(line);
1147         }
1148
1149         return 0;
1150 }
1151
1152 /*
1153  * end of csv import filter
1154  */
1155
1156 /*
1157  * csv addressbook export filter
1158  */
1159
1160 static int
1161 csv_export_database(FILE *out, struct db_enumerator e)
1162 {
1163         int j;
1164         int csv_export_fields[] = {
1165                 NAME,
1166                 EMAIL,
1167                 PHONE,
1168                 NOTES,
1169                 NICK,
1170                 -1
1171         };
1172
1173         db_enumerate_items(e) {
1174                 for(j = 0; csv_export_fields[j] >= 0; j++) {
1175                         fprintf(out,(
1176                 strchr(safe_str(database[e.item][csv_export_fields[j]]), ',') ||
1177                 strchr(safe_str(database[e.item][csv_export_fields[j]]), '\"')
1178                         ) ?
1179                                 "\"%s\"" : "%s",
1180                                 safe_str(database[e.item][csv_export_fields[j]])
1181                                 );
1182                         if(csv_export_fields[j+1] >= 0)
1183                                 fputc(',', out);
1184                 }
1185                 fputc('\n', out);
1186         }
1187                 
1188
1189
1190         return 0;
1191 }
1192
1193 /*
1194  * end of csv export filter
1195  */
1196
1197
1198 /*
1199  * GnomeCard (VCard) addressbook export filter
1200  */
1201
1202 static int
1203 gcrd_export_database(FILE *out, struct db_enumerator e)
1204 {
1205         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1206         int j;
1207         char *name;
1208
1209         db_enumerate_items(e) {
1210                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1211                                 safe_str(database[e.item][NAME]));
1212
1213                 name = get_surname(database[e.item][NAME]);
1214                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1215                         if(database[e.item][NAME][j] == ' ')
1216                                 break;
1217                 } 
1218                 fprintf(out, "N:%s;%.*s\n",
1219                         safe_str(name),
1220                         j,
1221                         safe_str(database[e.item][NAME])
1222                         ); 
1223
1224                 free(name);
1225
1226                 if ( database[e.item][ADDRESS] )
1227                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s;%s\n",
1228                                 safe_str(database[e.item][ADDRESS]),
1229                                 safe_str(database[e.item][ADDRESS2]),                           
1230                                 safe_str(database[e.item][CITY]),
1231                                 safe_str(database[e.item][STATE]),
1232                                 safe_str(database[e.item][ZIP]),
1233                                 safe_str(database[e.item][COUNTRY])
1234                                 );
1235                 
1236                 if (database[e.item][PHONE])
1237                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1238                 if (database[e.item][WORKPHONE])
1239                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1240                 if (database[e.item][FAX])
1241                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1242                 if (database[e.item][MOBILEPHONE])
1243                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1244
1245                 if ( database[e.item][EMAIL] ) {
1246                         split_emailstr(e.item, emails);
1247                         for(j=0; j < MAX_EMAILS ; j++) {
1248                                 if ( *emails[j] ) 
1249                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1250                                                 emails[j]);
1251                         }
1252                 }
1253                 
1254                 if ( database[e.item][NOTES] ) 
1255                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1256                 if (database[e.item][URL])
1257                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1258
1259                 fprintf(out, "END:VCARD\n\n");
1260                 
1261         }
1262
1263         return 0;
1264 }
1265
1266 /*
1267  * end of GnomeCard export filter
1268  */
1269
1270
1271 /*
1272  * mutt alias export filter
1273  */
1274
1275 static char *
1276 mutt_alias_genalias(int i)
1277 {
1278         char *tmp, *pos;
1279         
1280         if(database[i][NICK])
1281                 return strdup(database[i][NICK]);
1282
1283         tmp = strdup(database[i][NAME]);
1284
1285         if( ( pos = strchr(tmp, ' ') ) )
1286                 *pos = 0;
1287
1288         strlower(tmp);
1289
1290         return tmp;     
1291 }
1292
1293 static int
1294 mutt_alias_export(FILE *out, struct db_enumerator e)
1295 {
1296         char email[MAX_EMAIL_LEN];
1297         char *alias = NULL;
1298
1299         db_enumerate_items(e) {
1300                 alias = mutt_alias_genalias(e.item);
1301
1302                 get_first_email(email, e.item);
1303                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1304                                 alias,
1305                                 database[e.item][NAME],
1306                                 email);
1307                 my_free(alias);
1308         }
1309
1310         return 0;
1311 }
1312
1313 /*
1314  * end of mutt alias export filter
1315  */
1316
1317
1318 /*
1319  * printable export filter
1320  */
1321
1322
1323 static void
1324 text_write_address_us(FILE *out, int i) {
1325         fprintf(out, "\n%s", database[i][ADDRESS]);
1326
1327         if (database[i][ADDRESS2])
1328                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1329
1330         if (database[i][CITY])
1331                 fprintf(out, "\n%s", database[i][CITY]);
1332                 
1333         if (database[i][STATE] || database[i][ZIP]) {
1334                 fputc('\n', out);
1335                 
1336                 if(database[i][STATE]) {
1337                         fprintf(out, "%s", database[i][STATE]);
1338                         if(database[i][ZIP])
1339                                 fputc(' ', out);
1340                 }
1341
1342                 if(database[i][ZIP])
1343                         fprintf(out, "%s", database[i][ZIP]);
1344         }
1345
1346         if (database[i][COUNTRY])
1347                 fprintf(out, "\n%s", database[i][COUNTRY]);
1348 }
1349
1350
1351 static void
1352 text_write_address_uk(FILE *out, int i) {
1353         int j;
1354
1355         for (j = ADDRESS; j <= COUNTRY; j++)
1356                 if (database[i][j])
1357                         fprintf(out, "\n%s", database[i][j]);
1358 }
1359
1360 static void
1361 text_write_address_eu(FILE *out, int i) {
1362         fprintf(out, "\n%s", database[i][ADDRESS]);
1363
1364         if (database[i][ADDRESS2])
1365                 fprintf(out, "\n%s", database[i][ADDRESS2]);
1366
1367         if (database[i][ZIP] || database[i][CITY]) {
1368                 fputc('\n', out);
1369
1370                 if(database[i][ZIP]) {
1371                         fprintf(out, "%s", database[i][ZIP]);
1372                         if(database[i][CITY])
1373                                 fputc(' ', out);
1374                 }
1375
1376                 if(database[i][CITY])
1377                         fprintf(out, "%s", database[i][CITY]);
1378         }
1379         
1380         if (database[i][STATE])
1381                 fprintf(out, "\n%s", database[i][STATE]);
1382
1383         if (database[i][COUNTRY])
1384                 fprintf(out, "\n%s", database[i][COUNTRY]);
1385 }
1386
1387 static int
1388 text_export_database(FILE * out, struct db_enumerator e)
1389 {
1390         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1391         int j;
1392         char *realname = get_real_name();
1393         char *style = options_get_str("address_style");
1394
1395         fprintf(out,
1396                 "-----------------------------------------\n%s's address book\n"
1397                 "-----------------------------------------\n\n\n",
1398                 realname);
1399         free(realname);
1400
1401         db_enumerate_items(e) {
1402                 fprintf(out,
1403                         "-----------------------------------------\n\n");
1404                 fprintf(out, "%s", database[e.item][NAME]);
1405                 if (database[e.item][NICK])
1406                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1407                 fprintf(out, "\n");
1408
1409                 if (*database[e.item][EMAIL]) {
1410                         fprintf(out, "\n");
1411                         split_emailstr(e.item, emails);
1412                         for (j = 0; j < MAX_EMAILS; j++)
1413                                 if (*emails[j])
1414                                         fprintf(out, "%s\n", emails[j]);
1415                 }
1416                 /* Print address */
1417                 if (database[e.item][ADDRESS]) {
1418                         if (!safe_strcmp(style, "us"))  /* US like */
1419                                 text_write_address_us(out, e.item);
1420                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1421                                 text_write_address_uk(out, e.item);
1422                         else    /* EU like */
1423                                 text_write_address_eu(out, e.item);
1424
1425                         fprintf(out, "\n");
1426                 }
1427
1428                 if ((database[e.item][PHONE]) ||
1429                         (database[e.item][WORKPHONE]) ||
1430                         (database[e.item][FAX]) ||
1431                         (database[e.item][MOBILEPHONE])) {
1432                         fprintf(out, "\n");
1433                         for (j = PHONE; j <= MOBILEPHONE; j++)
1434                                 if (database[e.item][j])
1435                                         fprintf(out, "%s: %s\n",
1436                                                 abook_fields[j].name,
1437                                                 database[e.item][j]);
1438                 }
1439
1440                 if (database[e.item][URL])
1441                         fprintf(out, "\n%s\n", database[e.item][URL]);
1442                 if (database[e.item][NOTES])
1443                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1444
1445                 fprintf(out, "\n");
1446         }
1447
1448         fprintf(out, "-----------------------------------------\n");
1449
1450         return 0;
1451 }
1452
1453 /*
1454  * end of printable export filter
1455  */
1456
1457 /*
1458  * elm alias export filter
1459  */
1460
1461 static int
1462 elm_alias_export(FILE *out, struct db_enumerator e)
1463 {
1464         char email[MAX_EMAIL_LEN];
1465         char *alias = NULL;
1466
1467         db_enumerate_items(e) {
1468                 alias = mutt_alias_genalias(e.item);
1469                 get_first_email(email, e.item);
1470                 fprintf(out, "%s = %s = %s\n",
1471                                 alias,
1472                                 database[e.item][NAME],
1473                                 email);
1474                 my_free(alias);
1475         }
1476
1477         return 0;
1478 }
1479
1480 /*
1481  * end of elm alias export filter
1482  */
1483
1484
1485 /*
1486  * Spruce export filter
1487  */
1488
1489 static int
1490 spruce_export_database (FILE *out, struct db_enumerator e)
1491 {
1492         char email[MAX_EMAIL_LEN];
1493
1494         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1495
1496         db_enumerate_items(e) {
1497                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1498                         get_first_email(email, e.item);
1499                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1500                                         e.item,
1501                                         database[e.item][NAME],
1502                                         email,
1503                                         safe_str(database[e.item][NOTES])
1504                                         );
1505                 }
1506         }
1507
1508         fprintf (out, "# End of address book file.\n");
1509
1510         return 0;
1511 }
1512
1513 /*
1514  * end of Spruce export filter
1515  */
1516