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