]> git.deb.at Git - pkg/abook.git/blob - filter.c
getopt + fixes
[pkg/abook.git] / filter.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@users.sourceforge.net>
6  *
7  * Copyright (C) Jaakko Heinonen
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <ctype.h>
14 #include <pwd.h>
15 #include <sys/types.h>
16 #include "abook_curses.h"
17 #include "filter.h"
18 #include "abook.h"
19 #include "database.h"
20 #include "edit.h"
21 #include "list.h"
22 #include "misc.h"
23 #include "options.h"
24 #include <assert.h>
25
26 extern int items;
27 extern list_item *database;
28 extern struct abook_field abook_fields[];
29
30 /*
31  * function declarations
32  */
33
34 /*
35  * import filter prototypes
36  */
37
38 static int      ldif_parse_file(FILE *handle);
39 static int      mutt_parse_file(FILE *in);
40 static int      pine_parse_file(FILE *in);
41 static int      csv_parse_file(FILE *in);
42
43 /*
44  * export filter prototypes
45  */
46
47 static int      ldif_export_database(FILE *out, struct db_enumerator e);
48 static int      html_export_database(FILE *out, struct db_enumerator e);
49 static int      pine_export_database(FILE *out, struct db_enumerator e);
50 static int      csv_export_database(FILE *out, struct db_enumerator e);
51 static int      gcrd_export_database(FILE *out, struct db_enumerator e);
52 static int      mutt_alias_export(FILE *out, struct db_enumerator e);
53 static int      elm_alias_export(FILE *out, struct db_enumerator e);
54 static int      text_export_database(FILE *out, struct db_enumerator e);
55 static int      spruce_export_database(FILE *out, struct db_enumerator e);
56
57 /*
58  * end of function declarations
59  */
60
61 struct abook_input_filter i_filters[] = {
62         { "abook", "abook native format", parse_database },
63         { "ldif", "ldif / Netscape addressbook", ldif_parse_file },
64         { "mutt", "mutt alias", mutt_parse_file },
65         { "pine", "pine addressbook", pine_parse_file },
66         { "csv", "comma separated values", csv_parse_file },
67         { "\0", NULL, NULL }
68 };
69
70 struct abook_output_filter e_filters[] = {
71         { "abook", "abook native format", write_database },
72         { "ldif", "ldif / Netscape addressbook (.4ld)", ldif_export_database },
73         { "mutt", "mutt alias", mutt_alias_export },
74         { "html", "html document", html_export_database },
75         { "pine", "pine addressbook", pine_export_database },
76         { "gcrd", "GnomeCard (VCard) addressbook", gcrd_export_database },
77         { "csv", "comma separated values", csv_export_database },
78         { "elm", "elm alias", elm_alias_export },
79         { "text", "plain text", text_export_database },
80         { "spruce", "Spruce address book", spruce_export_database },
81         { "\0", NULL, NULL }
82 };
83
84 /*
85  * common functions
86  */
87
88 void
89 print_filters()
90 {
91         int i;
92         
93         puts("input:");
94         for(i=0; *i_filters[i].filtname ; i++)
95                 printf("\t%s\t%s\n", i_filters[i].filtname,
96                         i_filters[i].desc);
97
98         putchar('\n');
99         
100         puts("output:");
101         for(i=0; *e_filters[i].filtname ; i++)
102                 printf("\t%s\t%s\n", e_filters[i].filtname,
103                         e_filters[i].desc);
104
105         putchar('\n');
106 }
107
108 static int
109 number_of_output_filters()
110 {
111         int i;
112
113         for(i=0; *e_filters[i].filtname ; i++)
114                 ;
115
116         return i;
117 }
118
119 static int
120 number_of_input_filters()
121 {
122         int i;
123
124         for(i=0; *i_filters[i].filtname ; i++)
125                 ;
126
127         return i;
128 }
129
130 static char *
131 get_real_name()
132 {
133         char *username = getenv("USER");
134         struct passwd *pwent;
135         int rtn;
136         char *tmp;
137
138         pwent = getpwnam(username);
139
140         if( (tmp = (char *)malloc(strlen(pwent->pw_gecos) +1)) == NULL)
141                 return strdup(username);
142
143         rtn = sscanf(pwent->pw_gecos, "%[^,]", tmp);
144         if (rtn == EOF || rtn == 0) {
145                 free(tmp);
146                 return strdup(username);
147         } else
148                 return tmp;
149 }
150
151 /*
152  * import
153  */
154         
155 static int              i_read_file(char *filename, int (*func) (FILE *in));
156
157 static void
158 import_screen()
159 {
160         int i;
161         
162         clear();
163
164         refresh_statusline();
165         headerline("import database");
166
167         mvaddstr(3, 1, "please select a filter");
168         
169
170         for(i=0; *i_filters[i].filtname ; i++)
171                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
172                         i_filters[i].filtname,
173                         i_filters[i].desc);
174
175         mvprintw(6 + i, 6, "x -\tcancel");
176 }
177
178 int
179 import_database()
180 {
181         int filter;
182         char *filename;
183         int tmp = items;
184
185         import_screen();
186         
187         filter = getch() - 'a';
188         if(filter == 'x' - 'a' ||
189                 filter >= number_of_input_filters() || filter < 0) {
190                 refresh_screen();
191                 return 1;
192         }
193         
194         mvaddstr(5+filter, 2, "->");
195         
196         filename = ask_filename("Filename: ", 1);
197         if( !filename ) {
198                 refresh_screen();
199                 return 2;
200         }
201                 
202         if(  i_read_file(filename, i_filters[filter].func ) )
203                 statusline_msg("Error occured while opening the file");
204         else
205         if( tmp == items )
206                 statusline_msg("Hmm.., file seems not to be a valid file");
207         
208         refresh_screen();
209         free(filename);
210
211         return 0;
212 }
213
214
215
216 static int
217 i_read_file(char *filename, int (*func) (FILE *in))
218 {
219         FILE *in;
220         int ret = 0;
221
222         if( ( in = fopen( filename, "r" ) ) == NULL )
223                 return 1;
224
225         ret = (*func) (in);
226
227         fclose(in);
228
229         return ret;     
230 }
231
232 int
233 import_file(char filtname[FILTNAME_LEN], char *filename)
234 {
235         int i;
236         int tmp = items;
237         int ret = 0;
238
239         for(i=0;; i++) {
240                 if( ! strncasecmp(i_filters[i].filtname, filtname,
241                                         FILTNAME_LEN) )
242                         break;
243                 if( ! *i_filters[i].filtname ) {
244                         i = -1;
245                         break;
246                 }
247         }
248
249         if( i<0 )
250                 return -1;
251
252         if( !strcmp(filename, "-") )
253                 ret = (*i_filters[i].func) (stdin);
254         else
255                 ret =  i_read_file(filename, i_filters[i].func);
256         
257         if( tmp == items )
258                 ret = 1;
259         
260         return ret;
261 }
262
263 /*
264  * export
265  */
266
267 static int              e_write_file(char *filename,
268                 int (*func) (FILE *in, struct db_enumerator e), int mode);
269
270 static void
271 export_screen()
272 {
273         int i;
274         
275         clear();
276
277
278         refresh_statusline();
279         headerline("export database");
280
281         mvaddstr(3, 1, "please select a filter");
282         
283
284         for(i=0; *e_filters[i].filtname ; i++)
285                 mvprintw(5 + i, 6, "%c -\t%s\t%s\n", 'a' + i,
286                         e_filters[i].filtname,
287                         e_filters[i].desc);
288
289         mvprintw(6 + i, 6, "x -\tcancel");
290 }
291
292 int
293 export_database()
294 {
295         int filter;
296         int enum_mode = ENUM_ALL;
297         char *filename;
298
299         export_screen();
300         
301         filter = getch() - 'a';
302         if(filter == 'x' - 'a' ||
303                 filter >= number_of_output_filters() || filter < 0) {
304                 refresh_screen();
305                 return 1;
306         }
307         
308         mvaddstr(5+filter, 2, "->");
309
310         if( selected_items() ) {
311                 statusline_addstr("Export All/Selected/Cancel (A/s/c)");
312                 switch( tolower(getch()) ) {
313                         case 's':
314                                 enum_mode = ENUM_SELECTED;
315                                 break;
316                         case 'c':
317                                 clear_statusline();
318                                 return 1;
319                 }
320                 clear_statusline();
321         }
322         
323         filename = ask_filename("Filename: ", 0);
324         if( !filename ) {
325                 refresh_screen();
326                 return 2;
327         }
328         
329         if(  e_write_file(filename, e_filters[filter].func, enum_mode ) )
330                 statusline_msg("Error occured while exporting");
331         
332         refresh_screen();
333         free(filename);
334
335         return 0;
336 }
337
338 static int
339 e_write_file(char *filename, int (*func) (FILE *in, struct db_enumerator e),
340                 int mode)
341 {
342         FILE *out;
343         int ret = 0;
344         struct db_enumerator enumerator = init_db_enumerator(mode);
345
346         if( (out = fopen(filename, "a")) == NULL )
347                 return 1;
348
349         if( ftell(out) )
350                 return 1;
351
352         ret = (*func) (out, enumerator);
353         
354         fclose(out);
355         
356         return ret;
357 }
358
359 int
360 fexport(char filtname[FILTNAME_LEN], FILE *handle, int enum_mode)
361 {
362         int i;
363         struct db_enumerator e = init_db_enumerator(enum_mode);
364
365         for(i=0;; i++) {
366                 if( ! strncasecmp(e_filters[i].filtname, filtname,
367                                         FILTNAME_LEN) )
368                         break;
369                 if( ! *e_filters[i].filtname ) {
370                         i = -1;
371                         break;
372                 }
373         }
374
375         return (e_filters[i].func) (handle, e);
376 }
377
378         
379
380 int
381 export_file(char filtname[FILTNAME_LEN], char *filename)
382 {
383         const int mode = ENUM_ALL;
384         int i;
385         int ret = 0;
386         struct db_enumerator e = init_db_enumerator(mode);
387         
388         for(i=0;; i++) {
389                 if( ! strncasecmp(e_filters[i].filtname, filtname,
390                                         FILTNAME_LEN) )
391                         break;
392                 if( ! *e_filters[i].filtname ) {
393                         i = -1;
394                         break;
395                 }
396         }
397
398         if( i<0 )
399                 return -1;
400
401         if( !strcmp(filename, "-") )
402                 ret = (e_filters[i].func) (stdout, e);
403         else
404                 ret =  e_write_file(filename, e_filters[i].func, mode);
405
406         return ret;
407 }
408
409 /*
410  * end of common functions
411  */
412
413 /*
414  * ldif import
415  */
416
417 #include "ldif.h"
418
419 static void     ldif_fix_string(char *str);
420
421 #define LDIF_ITEM_FIELDS        16
422
423 typedef char*  ldif_item[LDIF_ITEM_FIELDS];
424
425 static ldif_item ldif_field_names = {
426         "cn",   
427         "mail",
428         "streetaddress",
429         "streetaddress2",
430         "locality",
431         "st",
432         "postalcode",
433         "countryname",
434         "homephone",
435         "description",
436         "homeurl",
437         "facsimiletelephonenumber",
438         "cellphone",
439         "xmozillaanyphone",
440         "xmozillanickname",
441         "objectclass", /* this must be the last entry */
442 };
443
444 static int ldif_conv_table[LDIF_ITEM_FIELDS] = {
445         NAME,           /* "cn" */
446         EMAIL,          /* "mail" */
447         ADDRESS,        /* "streetaddress" */
448         ADDRESS2,       /* "streetaddress2" */     
449         CITY,           /* "locality" */
450         STATE,          /* "st" */
451         ZIP,            /* "postalcode" */
452         COUNTRY,        /* "countryname" */
453         PHONE,          /* "homephone" */
454         NOTES,          /* "description" */
455         URL,            /* "homeurl" */
456         FAX,            /* "facsimiletelephonenumber" */
457         MOBILEPHONE,    /* "cellphone" */
458         WORKPHONE,      /* "xmozillaanyphone" */
459         NICK,           /* "xmozillanickname" */
460         -1,             /* "objectclass" */ /* this must be the last entry */
461 };
462
463
464 static char * 
465 ldif_read_line(FILE *in)
466 {
467         char *buf = NULL;
468         char *ptr, *tmp;
469         long pos;
470         int i;
471
472         for(i = 1;;i++) {
473                 char *line;
474
475                 pos = ftell(in);
476                 line = getaline(in);
477                 
478                 if( feof(in) || !line )
479                         break;
480                 
481                 if(i == 1) {
482                         buf = line;
483                         continue;
484                 }
485                 
486                 if(*line != ' ') {
487                         fseek(in, pos, SEEK_SET);
488                         free(line);
489                         break;
490                 }
491
492                 ptr = line;
493                 while( *ptr == ' ')
494                         ptr++;
495
496                 tmp = buf;
497                 buf = strconcat(buf, ptr, NULL);
498                 free(tmp);
499                 free(line);
500         }
501
502         if( *buf == '#' ) {
503                 free(buf);
504                 return NULL;
505         }
506                 
507         return buf;
508 }
509
510 static void
511 ldif_add_item(ldif_item ldif_item)
512 {
513         list_item abook_item;
514         int i;
515
516         memset(abook_item, 0, sizeof(abook_item));
517         
518         if( !ldif_item[LDIF_ITEM_FIELDS -1] )
519                 goto bail_out;
520         
521
522         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
523                 if(ldif_conv_table[i] >= 0 && ldif_item[i] && *ldif_item[i] )
524                         abook_item[ldif_conv_table[i]] = strdup(ldif_item[i]);
525         }
526
527         add_item2database(abook_item);
528
529 bail_out:
530         for(i=0; i < LDIF_ITEM_FIELDS; i++)
531                 my_free(ldif_item[i]);
532
533 }
534
535 static void
536 ldif_convert(ldif_item item, char *type, char *value)
537 {
538         int i;
539
540         if( !strcmp(type, "dn") ) {
541                 ldif_add_item(item);
542                 return;
543         }
544
545         for(i=0; i < LDIF_ITEM_FIELDS; i++) {
546                 if( !safe_strcmp(ldif_field_names[i], type) && *value ) {
547                         if( i == LDIF_ITEM_FIELDS -1) /* this is a dirty hack */
548                                 if( safe_strcmp("person", value))
549                                         break;
550                         if(item[i])
551                                 my_free(item[i]);
552                         item[i] = strdup(value);
553                 }
554         }
555 }
556
557 static int
558 ldif_parse_file(FILE *handle)
559 {
560         char *line = NULL;
561         char *type, *value;
562         int vlen;
563         ldif_item item;
564
565         memset(item, 0, sizeof(item));
566
567         do {
568                 if( ! (line = ldif_read_line(handle)) )
569                         continue;
570
571                 if( -1 == ( str_parse_line(line, &type, &value, &vlen)) ) {
572                         my_free(line);
573                         continue; /* just skip the errors */
574                 }
575                                 
576                 ldif_fix_string(value);
577
578                 ldif_convert(item, type, value);
579
580                 my_free(line);
581         } while ( !feof(handle) );
582
583         ldif_convert(item, "dn", "");
584
585         return 0;
586 }
587
588 static void
589 ldif_fix_string(char *str)
590 {
591         int i, j;
592
593         for( i = 0, j = 0; j < (int)strlen(str); i++, j++)
594                 str[i] = ( str[j] == (char)0xc3 ?
595                                 (char) str[++j] + (char) 0x40 :
596                                 str[j] );
597
598         str[i] = 0;
599 }
600
601 /*
602  * end of ldif import
603  */
604
605 /*
606  * mutt alias import filter
607  */
608
609 #include "getname.h"
610
611 static int
612 mutt_read_line(FILE *in, char **alias, char **rest)
613 {
614         char *line, *ptr, *tmp;
615
616         if( !(line = ptr = getaline(in)) )
617                 return 1; /* error / EOF */
618
619         while( ISSPACE(*ptr) )
620                 ptr++;
621
622         if( strncmp("alias", ptr, 5) ) {
623                 free(line);
624                 return 1;
625         }
626                 
627         ptr += 5;
628
629         while( ISSPACE(*ptr) )
630                 ptr++;
631
632         tmp = ptr;
633
634         while( ! ISSPACE(*ptr) )
635                 ptr++;
636
637         if( (*alias = (char *)malloc(ptr-tmp+1)) == NULL) {
638                 free(line);
639                 return 1;
640         }
641
642         strncpy(*alias, tmp, ptr-tmp);
643         *(*alias + (ptr - tmp)) = 0;
644
645         while( ISSPACE(*ptr) )
646                 ptr++;
647
648         *rest = strdup(ptr);    
649
650         free(line);
651         return 0;
652 }
653
654 static void
655 mutt_parse_email(list_item item)
656 {
657         char *line = item[NAME];
658         char *start = line, *tmp;
659         char *name, *email;
660         int i = 0;
661
662         tmp = strconcat("From: ", line, NULL);
663         getname(tmp, &name, &email);
664         free(tmp);
665
666         if(name)
667                 item[NAME] = name;
668         else
669                 return;
670         if(email)
671                 item[EMAIL] = email;
672         else
673                 return;
674         
675         while( (start = strchr(start, ',')) && i++ < MAX_EMAILS - 1) {
676                 tmp = strconcat("From: ", ++start, NULL);
677                 getname(tmp, &name, &email);
678                 free(tmp);
679                 free(name);
680                 if(email) {
681                         if(*email) {
682                                 tmp = strconcat(item[EMAIL], ",", email, NULL);
683                                 free(item[EMAIL]);
684                                 item[EMAIL] = tmp;
685                         } else {
686                                 my_free(email);
687                         }
688                 }
689         }
690 }
691
692 static int
693 mutt_parse_file(FILE *in)
694 {
695         list_item item;
696
697         for(;;) {
698                 memset(item, 0, sizeof(item));
699                 
700                 if( !mutt_read_line(in, &item[NICK],
701                                 &item[NAME]) )
702                         mutt_parse_email(item);
703
704                 if( feof(in) ) {
705                         free_list_item(item);
706                         break;
707                 }
708
709                 add_item2database(item);
710         }
711
712         return 0;
713 }
714
715 /*
716  * end of mutt alias import filter
717  */
718
719
720 /*
721  * ldif export filter
722  */
723
724 static void
725 ldif_fput_type_and_value(FILE *out,char *type, char *value )
726 {
727         char *tmp;
728
729         tmp = ldif_type_and_value(type, value, strlen(value));
730
731         fputs(tmp, out);
732
733         free(tmp);
734 }
735
736 static int
737 ldif_export_database(FILE *out, struct db_enumerator e)
738 {
739         char email[MAX_EMAILSTR_LEN];
740
741         fprintf(out, "version: 1\n");
742
743         db_enumerate_items(e) {
744                 char *tmp;
745                 int j;
746                 get_first_email(email, e.item);
747
748                 tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
749                 ldif_fput_type_and_value(out, "dn", tmp);
750                 free(tmp);
751
752                 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
753                         if(ldif_conv_table[j] >= 0) {
754                                 if(ldif_conv_table[j] == EMAIL)
755                                         ldif_fput_type_and_value(out,
756                                                 ldif_field_names[j], email);
757                                 else if(database[e.item][ldif_conv_table[j]])
758                                         ldif_fput_type_and_value(out,
759                                                 ldif_field_names[j],
760                                                 database[e.item][ldif_conv_table[j]]);
761                         }
762                 }
763
764                 fprintf(out, "objectclass: top\n"
765                                 "objectclass: person\n\n");
766         }
767
768         return 0;
769 }
770
771 /*
772  * end of ldif export filter
773  */
774
775 /*
776  * html export filter
777  */
778
779 static void            html_export_write_head(FILE *out, int extra_column);
780 static void            html_export_write_tail(FILE *out);
781
782 static int
783 html_export_database(FILE *out, struct db_enumerator e)
784 {
785         char tmp[MAX_EMAILSTR_LEN];
786         int extra_column = options_get_int("extra_column");
787
788         if( items < 1 )
789                 return 2;
790
791         extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
792                 extra_column : PHONE;
793
794         html_export_write_head(out, extra_column);
795
796         db_enumerate_items(e) {
797                 get_first_email(tmp, e.item);
798                 if (*tmp)
799                     fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
800                             tmp,
801                             database[e.item][NAME] );
802                 else
803                     fprintf(out, "<tr>\n<td>%s\n",
804                             database[e.item][NAME] );
805
806                 fprintf(out, "<td>%s\n<td>%s\n",
807                                 database[e.item][EMAIL],
808                                 safe_str(database[e.item][extra_column]) );
809                 fprintf(out, "</tr>\n\n");
810         }
811
812         html_export_write_tail(out);
813
814         return 0;
815 }
816
817
818 static void
819 html_export_write_head(FILE *out, int extra_column)
820 {
821         char *realname = get_real_name();
822
823         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
824         fprintf(out, "<html>\n<head>\n  <title>%s's addressbook</title>",
825                         realname );
826         fprintf(out, "\n</head>\n<body>\n");
827         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
828         fprintf(out, "<br><br>\n\n");
829
830         fprintf(out, "<center><table border>\n");
831         fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
832                         abook_fields[extra_column].name);
833
834         free(realname);
835 }
836
837 static void
838 html_export_write_tail(FILE *out)
839 {
840         fprintf(out, "\n</table></center>\n");
841         fprintf(out, "\n</body>\n</html>\n");
842 }
843         
844 /*
845  * end of html export filter
846  */
847
848
849 /*
850  * pine addressbook import filter
851  */
852
853 static void
854 pine_fixbuf(char *buf)
855 {
856         int i,j;
857
858         for(i=0,j=0; j < (int)strlen(buf); i++, j++)
859                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
860 }
861
862 static void
863 pine_convert_emails(char *s)
864 {
865         int i;
866         char *tmp;
867
868         if( s == NULL || *s != '(' )
869                 return;
870
871         for(i=0; s[i]; i++ )
872                 s[i] = s[i+1];
873
874         if( ( tmp = strchr(s,')')) )
875                 *tmp=0;
876         
877         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
878                 if( i > MAX_EMAILS - 1 ) {
879                         *tmp = 0;
880                         break;  
881                 }
882
883 }
884
885 static void
886 pine_parse_buf(char *buf)
887 {
888         list_item item;
889         char *start = buf;
890         char *end;
891         char tmp[400];
892         int i, len, last;
893         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
894
895         memset(&item, 0, sizeof(item) );
896         
897         for(i=0, last=0; !last ; i++) {
898                 if( ! (end = strchr(start, '\t')) )
899                         last=1;
900                 
901                 len = last ? strlen(start) : (int) (end-start);
902                 len = min(len, 400-1);
903         
904                 if(i < (int)(sizeof(pine_conv_table) / sizeof(*pine_conv_table))
905                                 && pine_conv_table[i] >= 0) {
906                         strncpy(tmp, start, len);
907                         tmp[len] = 0;
908                         item[pine_conv_table[i]] = strdup(tmp);
909                 }
910                 start = end + 1;
911         }
912         
913         pine_convert_emails(item[EMAIL]);
914         add_item2database(item);
915 }
916                 
917
918 #define LINESIZE        1024
919
920 static int
921 pine_parse_file(FILE *in)
922 {
923         char line[LINESIZE];
924         char *buf = NULL;
925         char *ptr;
926         int i;
927
928         fgets(line, LINESIZE, in);      
929         
930         while(!feof(in)) {
931                 for(i = 2;;i++) {
932                         buf = (char *) realloc(buf, i*LINESIZE);
933                         if(i == 2)
934                                 strcpy(buf, line);
935                         fgets(line, LINESIZE, in);
936                         ptr=(char *)&line;
937                         if(*ptr != ' ' || feof(in) )
938                                 break;
939                         else
940                                 while( *ptr == ' ')
941                                         ptr++;
942                                 
943                         strcat(buf, ptr);
944                 }
945                 if( *buf == '#' ) {
946                         my_free(buf);
947                         continue;
948                 }
949                 pine_fixbuf(buf);
950
951                 pine_parse_buf(buf);
952
953                 my_free(buf);
954         }
955
956         return 0;
957 }
958
959 /*
960  * end of pine addressbook import filter
961  */
962
963
964 /*
965  * pine addressbook export filter
966  *
967  *  filter doesn't wrap the lines as it should but Pine seems to handle
968  *  created files without problems - JH
969  */
970
971 static int
972 pine_export_database(FILE *out, struct db_enumerator e)
973 {
974         db_enumerate_items(e) {
975                 fprintf(out, have_multiple_emails(e.item) ?
976                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
977                                 safe_str(database[e.item][NICK]),
978                                 safe_str(database[e.item][NAME]),
979                                 safe_str(database[e.item][EMAIL]),
980                                 safe_str(database[e.item][NOTES])
981                                 );
982         }
983
984         return 0;
985 }
986
987 /*
988  * end of pine addressbook export filter
989  */
990
991
992 /*
993  * csv import filter
994  */
995
996 /* FIXME
997  * these files should be parsed according to a certain
998  * lay out, or the default if layout is not given, at 
999  * the moment only default is done...
1000  */ 
1001
1002 #define CSV_COMMENT_CHAR        '#'
1003
1004 static int csv_conv_table[] = {
1005         NAME,
1006         EMAIL,
1007         PHONE,
1008         NOTES,
1009         NICK
1010 };
1011
1012 static void
1013 csv_convert_emails(char *s)
1014 {
1015         int i;
1016         char *tmp;
1017
1018         if( s == NULL )
1019                 return;
1020
1021         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1022                 if( i > MAX_EMAILS - 1 ) {
1023                         *tmp = 0;
1024                         break;  
1025                 }
1026
1027 }
1028
1029 static char *
1030 csv_remove_quotes(char *s)
1031 {
1032         char *copy, *trimmed;
1033         int len;
1034         
1035         copy = trimmed = strdup(s);
1036         strtrim(trimmed);
1037         
1038         len = strlen(trimmed);
1039         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1040                 if(len < 3) {
1041                         my_free(copy);
1042                         return NULL;
1043                 }
1044                 trimmed[len - 1] = 0;
1045                 trimmed++;
1046                 trimmed = strdup(trimmed);
1047                 free(copy);
1048                 return trimmed;
1049         }
1050
1051         my_free(copy);
1052         return strdup(s);
1053 }
1054
1055 static void
1056 csv_store_field(list_item item, char *s, int field)
1057 {
1058         char *newstr = NULL;
1059
1060         if(!s || !*s)
1061                 return;
1062
1063         if( !(newstr = csv_remove_quotes(s)) )
1064                 return;
1065
1066         if(field < (int)(sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1067                         && csv_conv_table[field] >= 0) {
1068                 item[csv_conv_table[field]] = newstr;
1069         } else {
1070                 my_free(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