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