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