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