]> git.deb.at Git - pkg/abook.git/blob - filter.c
Merged csv import filter
[pkg/abook.git] / filter.c
1
2 /*
3  * $Id$
4  *
5  * by JH <jheinonen@bigfoot.com>
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 #ifndef LINESIZE
419 #       define LINESIZE 1024
420 #endif
421
422 #define LDIF_ITEM_FIELDS        15
423
424 typedef char*  ldif_item[LDIF_ITEM_FIELDS];
425
426 static ldif_item ldif_field_names = {
427         "cn",   
428         "mail",
429         "streetaddress",
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         CITY,           /* "locality" */
449         STATE,          /* "st" */
450         ZIP,            /* "postalcode" */
451         COUNTRY,        /* "countryname" */
452         PHONE,          /* "homephone" */
453         NOTES,          /* "description" */
454         URL,            /* "homeurl" */
455         FAX,            /* "facsimiletelephonenumber" */
456         MOBILEPHONE,    /* "cellphone" */
457         WORKPHONE,      /* "xmozillaanyphone" */
458         NICK,           /* "xmozillanickname" */
459         -1,             /* "objectclass" */ /* this must be the last entry */
460 };
461
462
463 static char * 
464 ldif_read_line(FILE *in)
465 {
466         char line[LINESIZE];
467         char *buf=NULL;
468         char *ptr, *tmp;
469         long pos;
470         int i;
471
472         for(i=1;;i++) {
473                 pos = ftell(in);
474                 fgets(line, LINESIZE, in);
475                 
476                 if( feof(in) )
477                         break;
478                 
479                 if(i == 1) {
480                         buf = strdup(line);
481                         continue;
482                 }
483                 
484                 if(*line != ' ') {
485                         fseek(in, pos, SEEK_SET);
486                         break;
487                 }
488
489                 ptr = (char *)&line;
490                 while( *ptr == ' ')
491                         ptr++;
492
493                 tmp = buf;
494                 buf = strconcat(buf, ptr, NULL);
495                 free(tmp);
496         }
497
498         if( *buf == '#' ) {
499                 free(buf);
500                 return NULL;
501         }
502                 
503         if(buf) {
504                 int i,j;
505                 for(i=0,j=0; j < strlen(buf); i++, j++)
506                         buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
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 enum {
612         MUTT_ALIAS,
613         MUTT_NAME,
614         MUTT_EMAIL
615 };
616
617 static void
618 remove_newlines(char *buf)
619 {
620         int i,j;
621         
622         for(i=0,j=0; j < strlen(buf); i++, j++)
623                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
624 }
625
626 static int
627 mutt_read_line(FILE *in, char **alias, char **rest)
628 {
629         char line[LINESIZE];
630         char *ptr=(char *)&line;
631         char *tmp;
632
633         fgets(line, LINESIZE, in);
634         remove_newlines(line);
635
636         while( ISSPACE(*ptr) )
637                 ptr++;
638
639         if( strncmp("alias", ptr, 5) ) {
640                 return 1;
641         }
642                 
643         ptr += 5;
644
645         while( ISSPACE(*ptr) )
646                 ptr++;
647
648         tmp = ptr;
649
650         while( ! ISSPACE(*ptr) )
651                 ptr++;
652
653         if( (*alias = (char *)malloc(ptr-tmp+1)) == NULL)
654                 return 1;
655
656         strncpy(*alias, tmp, ptr-tmp);
657         *(*alias+(ptr-tmp)) = 0;
658
659         while( ISSPACE(*ptr) )
660                 ptr++;
661
662         *rest = strdup(ptr);    
663         
664         return 0;
665 }
666
667 static void
668 mutt_parse_email(char *mutt_item[3])
669 {
670         char *tmp;
671         int i;
672
673         if( (tmp = strchr(mutt_item[MUTT_NAME], '<')) )
674                 *tmp = 0;
675         else
676                 return;
677
678         mutt_item[MUTT_EMAIL] = strdup(tmp+1);
679
680         if( (tmp = strchr(mutt_item[MUTT_EMAIL], '>')) )
681                 *tmp = 0;
682
683         tmp = mutt_item[MUTT_NAME];
684
685         for(i=strlen(tmp)-1; i>0; i--)
686                 if(ISSPACE(tmp[i]))
687                         tmp[i] = 0;
688                 else
689                         break;
690
691         mutt_item[MUTT_NAME] = strdup(tmp);
692
693         free(tmp);
694 }
695
696 static void
697 mutt_add_mutt_item(char *mutt_item[3])
698 {
699         list_item abook_item;
700
701         memset(abook_item, 0, sizeof(abook_item));
702
703         abook_item[NAME] = safe_strdup(mutt_item[MUTT_NAME]);
704         abook_item[EMAIL] = safe_strdup(mutt_item[MUTT_EMAIL]);
705         abook_item[NICK] = safe_strdup(mutt_item[MUTT_ALIAS]);
706
707         add_item2database(abook_item);
708 }
709
710 static int
711 mutt_parse_file(FILE *in)
712 {
713         char *mutt_item[3];
714
715         for(;;) {
716
717                 memset(mutt_item, 0, sizeof(mutt_item) );
718                 
719                 if( mutt_read_line(in, &mutt_item[MUTT_ALIAS],
720                                 &mutt_item[MUTT_NAME]) )
721                         continue;
722
723                 mutt_parse_email(mutt_item);
724
725                 if( feof(in) ) {
726                         free(mutt_item[MUTT_ALIAS]);
727                         free(mutt_item[MUTT_NAME]);
728                         free(mutt_item[MUTT_EMAIL]);
729                         break;
730                 }
731
732                 mutt_add_mutt_item(mutt_item);
733
734                 free(mutt_item[MUTT_ALIAS]);
735                 free(mutt_item[MUTT_NAME]);
736                 free(mutt_item[MUTT_EMAIL]);
737         }
738
739
740         return 0;
741 }
742
743 /*
744  * end of mutt alias import filter
745  */
746
747
748 /*
749  * ldif export filter
750  */
751
752 static void
753 ldif_fput_type_and_value(FILE *out,char *type, char *value )
754 {
755         char *tmp;
756
757         tmp = ldif_type_and_value(type, value, strlen(value));
758
759         fputs(tmp, out);
760
761         free(tmp);
762 }
763
764 static int
765 ldif_export_database(FILE *out, struct db_enumerator e)
766 {
767         char email[MAX_EMAILSTR_LEN];
768
769         fprintf(out, "version: 1\n");
770
771         db_enumerate_items(e) {
772                 char *tmp;
773                 int j;
774                 get_first_email(email, e.item);
775
776                 tmp = mkstr("cn=%s,mail=%s", database[e.item][NAME], email);
777                 ldif_fput_type_and_value(out, "dn", tmp);
778                 free(tmp);
779
780                 for(j=0; j < LDIF_ITEM_FIELDS; j++) {
781                         if(ldif_conv_table[j] >= 0) {
782                                 if(ldif_conv_table[j] == EMAIL)
783                                         ldif_fput_type_and_value(out,
784                                                 ldif_field_names[j], email);
785                                 else if(database[e.item][ldif_conv_table[j]])
786                                         ldif_fput_type_and_value(out,
787                                                 ldif_field_names[j],
788                                                 database[e.item][ldif_conv_table[j]]);
789                         }
790                 }
791
792                 fprintf(out, "objectclass: top\n"
793                                 "objectclass: person\n\n");
794         }
795
796         return 0;
797 }
798
799 /*
800  * end of ldif export filter
801  */
802
803 /*
804  * html export filter
805  */
806
807 static void            html_export_write_head(FILE *out, int extra_column);
808 static void            html_export_write_tail(FILE *out);
809
810 static int
811 html_export_database(FILE *out, struct db_enumerator e)
812 {
813         char tmp[MAX_EMAILSTR_LEN];
814         int extra_column = options_get_int("extra_column");
815
816         if( items < 1 )
817                 return 2;
818
819         extra_column = (extra_column > 2 && extra_column < ITEM_FIELDS) ?
820                 extra_column : PHONE;
821
822         html_export_write_head(out, extra_column);
823
824         db_enumerate_items(e) {
825                 get_first_email(tmp, e.item);
826                 if (*tmp)
827                     fprintf(out, "<tr>\n<td><a href=\"mailto:%s\">%s</a>\n",
828                             tmp,
829                             database[e.item][NAME] );
830                 else
831                     fprintf(out, "<tr>\n<td>%s>\n",
832                             database[e.item][NAME] );
833
834                 fprintf(out, "<td>%s\n<td>%s\n",
835                                 database[e.item][EMAIL],
836                                 safe_str(database[e.item][extra_column]) );
837                 fprintf(out, "</tr>\n\n");
838         }
839
840         html_export_write_tail(out);
841
842         return 0;
843 }
844
845
846 static void
847 html_export_write_head(FILE *out, int extra_column)
848 {
849         char *realname = get_real_name();
850
851         fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n");
852         fprintf(out, "<html>\n<head>\n  <title>%s's addressbook</title>",
853                         realname );
854         fprintf(out, "\n</head>\n<body>\n");
855         fprintf(out, "\n<h2>%s's addressbook</h2>\n", realname );
856         fprintf(out, "<br><br>\n\n");
857
858         fprintf(out, "<center><table border>\n");
859         fprintf(out, "\n<tr><th>Name<th>E-mail address(es)<th>%s</tr>\n\n",
860                         abook_fields[extra_column].name);
861
862         free(realname);
863 }
864
865 static void
866 html_export_write_tail(FILE *out)
867 {
868         fprintf(out, "\n</table></center>\n");
869         fprintf(out, "\n</body>\n</html>\n");
870 }
871         
872 /*
873  * end of html export filter
874  */
875
876
877 /*
878  * pine addressbook import filter
879  */
880
881 static void
882 pine_fixbuf(char *buf)
883 {
884         int i,j;
885
886         for(i=0,j=0; j < strlen(buf); i++, j++)
887                 buf[i] = buf[j] == '\n' ? buf[++j] : buf[j];
888 }
889
890 static void
891 pine_convert_emails(char *s)
892 {
893         int i;
894         char *tmp;
895
896         if( s == NULL || *s != '(' )
897                 return;
898
899         for(i=0; s[i]; i++ )
900                 s[i] = s[i+1];
901
902         if( ( tmp = strchr(s,')')) )
903                 *tmp=0;
904         
905         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s=tmp+1 )
906                 if( i > MAX_EMAILS - 1 ) {
907                         *tmp = 0;
908                         break;  
909                 }
910
911 }
912
913 static void
914 pine_parse_buf(char *buf)
915 {
916         list_item item;
917         char *start = buf;
918         char *end;
919         char tmp[400];
920         int i, len, last;
921         int pine_conv_table[]= {NICK, NAME, EMAIL, -1, NOTES};
922
923         memset(&item, 0, sizeof(item) );
924         
925         for(i=0, last=0; !last ; i++) {
926                 if( ! (end = strchr(start, '\t')) )
927                         last=1;
928                 
929                 len = last ? strlen(start) : (int) (end-start);
930                 len = min(len, 400-1);
931         
932                 if(i < sizeof(pine_conv_table) / sizeof(*pine_conv_table)
933                                 && pine_conv_table[i] >= 0) {
934                         strncpy(tmp, start, len);
935                         tmp[len] = 0;
936                         item[pine_conv_table[i]] = strdup(tmp);
937                 }
938                 start = end + 1;
939         }
940         
941         pine_convert_emails(item[EMAIL]);
942         add_item2database(item);
943 }
944                 
945
946 #define LINESIZE        1024
947
948 static int
949 pine_parse_file(FILE *in)
950 {
951         char line[LINESIZE];
952         char *buf=NULL;
953         char *ptr;
954         int i;
955
956         fgets(line, LINESIZE, in);      
957         
958         while(!feof(in)) {
959                 for(i=2;;i++) {
960                         buf = (char *) realloc(buf, i*LINESIZE);
961                         if(i==2)
962                                 strcpy(buf, line);
963                         fgets(line, LINESIZE, in);
964                         ptr=(char *)&line;
965                         if(*ptr != ' ' || feof(in) )
966                                 break;
967                         else
968                                 while( *ptr == ' ') ptr++;
969                                 
970                         strcat(buf, ptr);
971                 }
972                 if( *buf == '#' ) {
973                         my_free(buf);
974                         continue;
975                 }
976                 pine_fixbuf(buf);
977
978                 pine_parse_buf(buf);
979
980                 my_free(buf);
981         }
982
983         return 0;
984 }
985
986 /*
987  * end of pine addressbook import filter
988  */
989
990
991 /*
992  * pine addressbook export filter
993  *
994  *  filter doesn't wrap the lines as it should but Pine seems to handle
995  *  created files without problems - JH
996  */
997
998 static int
999 pine_export_database(FILE *out, struct db_enumerator e)
1000 {
1001         db_enumerate_items(e) {
1002                 fprintf(out, have_multiple_emails(e.item) ?
1003                                 "%s\t%s\t(%s)\t\t%s\n" : "%s\t%s\t%s\t\t%s\n",
1004                                 safe_str(database[e.item][NICK]),
1005                                 safe_str(database[e.item][NAME]),
1006                                 safe_str(database[e.item][EMAIL]),
1007                                 safe_str(database[e.item][NOTES])
1008                                 );
1009         }
1010
1011         return 0;
1012 }
1013
1014 /*
1015  * end of pine addressbook export filter
1016  */
1017
1018
1019 /*
1020  * csv import filter
1021  */
1022
1023 /* FIXME
1024  * these files should be parsed according to a certain
1025  * lay out, or the default if layout is not given, at 
1026  * the moment only default is done...
1027  */ 
1028
1029 #define CSV_COMMENT_CHAR        '#'
1030
1031 static int csv_conv_table[] = {
1032         NAME,
1033         EMAIL,
1034         PHONE,
1035         NOTES,
1036         NICK
1037 };
1038
1039 static void
1040 csv_convert_emails(char *s)
1041 {
1042         int i;
1043         char *tmp;
1044
1045         if( s == NULL )
1046                 return;
1047
1048         for(i=1; ( tmp = strchr(s, ',') ) != NULL ; i++, s = tmp + 1 )
1049                 if( i > MAX_EMAILS - 1 ) {
1050                         *tmp = 0;
1051                         break;  
1052                 }
1053
1054 }
1055
1056 static char *
1057 csv_remove_quotes(char *s)
1058 {
1059         char *copy, *trimmed;
1060         int len;
1061         
1062         copy = trimmed = strdup(s);
1063         strtrim(trimmed);
1064         
1065         len = strlen(trimmed);
1066         if(trimmed[len - 1] == '\"' && *trimmed == '\"') {
1067                 if(len < 3) {
1068                         my_free(copy);
1069                         return NULL;
1070                 }
1071                 trimmed[len - 1] = 0;
1072                 trimmed++;
1073                 trimmed = strdup(trimmed);
1074                 free(copy);
1075                 return trimmed;
1076         }
1077
1078         my_free(copy);
1079         return strdup(s);
1080 }
1081
1082 static void
1083 csv_store_field(list_item item, char *s, int field)
1084 {
1085         char *newstr = NULL;
1086
1087         if(!s || !*s)
1088                 return;
1089
1090         if( !(newstr = csv_remove_quotes(s)) )
1091                 return;
1092
1093         if(field < (sizeof(csv_conv_table) / sizeof(*csv_conv_table))
1094                         && csv_conv_table[field] >= 0) {
1095                 item[csv_conv_table[field]] = newstr;
1096         }
1097 }
1098
1099 static int
1100 csv_is_valid_quote_end(char *p)
1101 {
1102         if(*p != '\"')
1103                 return FALSE;
1104
1105         for(p++; *p; p++) {
1106                 if(*p == ',')
1107                         return TRUE;
1108                 else if(!ISSPACE(*p))
1109                         return FALSE;
1110         }
1111
1112         return TRUE;
1113 }
1114
1115 static int
1116 csv_is_valid_quote_start(char *p)
1117 {
1118         for(; *p; p++) {
1119                 if(*p == '\"')
1120                         return TRUE;
1121                 else if(!ISSPACE(*p))
1122                         return FALSE;
1123         }
1124
1125         return FALSE;
1126 }
1127
1128 static void
1129 csv_parse_line(char *line)
1130 {
1131         char *p, *start;
1132         int field;
1133         int in_quote = FALSE;
1134         list_item item;
1135
1136         memset(item, 0, sizeof(item));
1137
1138         for(p = start = line, field = 0; *p; p++) {
1139                 if(!in_quote) {
1140                         if ( (((p - start) / sizeof (char)) < 2 ) &&
1141                                 csv_is_valid_quote_start(p) )
1142                                 in_quote = TRUE;
1143                 } else {
1144                         if(csv_is_valid_quote_end(p))
1145                                 in_quote = FALSE;
1146                 }
1147
1148                 if( *p == ',' && !in_quote) {
1149                         *p = 0;
1150                         csv_store_field(item, start, field);
1151                         field++;
1152                         start = p + 1;
1153                 }
1154         }
1155         /*
1156          * store last field
1157          */
1158         csv_store_field(item, start, field);
1159
1160         csv_convert_emails(item[EMAIL]);
1161         add_item2database(item);
1162 }
1163
1164
1165 static int
1166 csv_parse_file(FILE *in)
1167 {
1168         char *line = NULL;
1169
1170         while(!feof(in)) {
1171                 line = getaline(in);
1172
1173                 if(line && *line && *line != CSV_COMMENT_CHAR)
1174                         csv_parse_line(line);
1175
1176                 my_free(line);
1177         }
1178
1179         return 0;
1180 }
1181
1182 /*
1183  * end of csv import filter
1184  */
1185
1186 /*
1187  * csv addressbook export filter
1188  */
1189
1190 static int
1191 csv_export_database(FILE *out, struct db_enumerator e)
1192 {
1193         int j;
1194         int csv_export_fields[] = {
1195                 NAME,
1196                 EMAIL,
1197                 PHONE,
1198                 NOTES,
1199                 NICK,
1200                 -1
1201         };
1202
1203         db_enumerate_items(e) {
1204                 for(j = 0; csv_export_fields[j] >= 0; j++) {
1205                         fprintf(out,(
1206                 strchr(safe_str(database[e.item][csv_export_fields[j]]), ',') ||
1207                 strchr(safe_str(database[e.item][csv_export_fields[j]]), '\"')
1208                         ) ?
1209                                 "\"%s\"" : "%s",
1210                                 safe_str(database[e.item][csv_export_fields[j]])
1211                                 );
1212                         if(csv_export_fields[j+1] >= 0)
1213                                 fputc(',', out);
1214                 }
1215                 fputc('\n', out);
1216         }
1217                 
1218
1219
1220         return 0;
1221 }
1222
1223 /*
1224  * end of csv export filter
1225  */
1226
1227
1228 /*
1229  * GnomeCard (VCard) addressbook export filter
1230  */
1231
1232 static int
1233 gcrd_export_database(FILE *out, struct db_enumerator e)
1234 {
1235         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1236         int j;
1237         char *name;
1238
1239         db_enumerate_items(e) {
1240                 fprintf(out, "BEGIN:VCARD\nFN:%s\n",
1241                                 safe_str(database[e.item][NAME]));
1242
1243                 name = get_surname(database[e.item][NAME]);
1244                 for( j = strlen(database[e.item][NAME]) - 1; j >= 0; j-- ) {
1245                         if(database[e.item][NAME][j] == ' ')
1246                                 break;
1247                 } 
1248                 fprintf(out, "N:%s;%.*s\n",
1249                         safe_str(name),
1250                         j,
1251                         safe_str(database[e.item][NAME])
1252                         ); 
1253
1254                 free(name);
1255
1256                 if ( database[e.item][ADDRESS] )
1257                         fprintf(out, "ADR:;;%s;%s;%s;%s;%s\n",
1258                                 safe_str(database[e.item][ADDRESS]),
1259                                 safe_str(database[e.item][CITY]),
1260                                 safe_str(database[e.item][STATE]),
1261                                 safe_str(database[e.item][ZIP]),
1262                                 safe_str(database[e.item][COUNTRY])
1263                                 );
1264                 
1265                 if (database[e.item][PHONE])
1266                         fprintf(out, "TEL;HOME:%s\n", database[e.item][PHONE]);
1267                 if (database[e.item][WORKPHONE])
1268                         fprintf(out, "TEL;WORK:%s\n", database[e.item][WORKPHONE]);
1269                 if (database[e.item][FAX])
1270                         fprintf(out, "TEL;FAX:%s\n", database[e.item][FAX]);
1271                 if (database[e.item][MOBILEPHONE])
1272                         fprintf(out, "TEL;CELL:%s\n", database[e.item][MOBILEPHONE]);
1273
1274                 if ( database[e.item][EMAIL] ) {
1275                         split_emailstr(e.item, emails);
1276                         for(j=0; j < MAX_EMAILS ; j++) {
1277                                 if ( *emails[j] ) 
1278                                         fprintf(out, "EMAIL;INTERNET:%s\n",
1279                                                 emails[j]);
1280                         }
1281                 }
1282                 
1283                 if ( database[e.item][NOTES] ) 
1284                         fprintf(out, "NOTE:%s\n", database[e.item][NOTES]);
1285                 if (database[e.item][URL])
1286                         fprintf(out, "URL:%s\n",  database[e.item][URL]);
1287
1288                 fprintf(out, "END:VCARD\n\n");
1289                 
1290         }
1291
1292         return 0;
1293 }
1294
1295 /*
1296  * end of GnomeCard export filter
1297  */
1298
1299
1300 /*
1301  * mutt alias export filter
1302  */
1303
1304 static char *
1305 mutt_alias_genalias(int i)
1306 {
1307         char *tmp, *pos;
1308         
1309         if(database[i][NICK])
1310                 return strdup(database[i][NICK]);
1311
1312         tmp = strdup(database[i][NAME]);
1313
1314         if( ( pos = strchr(tmp, ' ') ) )
1315                 *pos = 0;
1316
1317         strlower(tmp);
1318
1319         return tmp;     
1320 }
1321
1322 static int
1323 mutt_alias_export(FILE *out, struct db_enumerator e)
1324 {
1325         char email[MAX_EMAIL_LEN];
1326         char *alias = NULL;
1327
1328         db_enumerate_items(e) {
1329                 alias = mutt_alias_genalias(e.item);
1330
1331                 get_first_email(email, e.item);
1332                 fprintf(out, *email ? "alias %s %s <%s>\n": "alias %s %s%s\n",
1333                                 alias,
1334                                 database[e.item][NAME],
1335                                 email);
1336                 my_free(alias);
1337         }
1338
1339         return 0;
1340 }
1341
1342 /*
1343  * end of mutt alias export filter
1344  */
1345
1346
1347 /*
1348  * printable export filter
1349  */
1350
1351
1352 static void
1353 text_write_address_us(FILE *out, int i) {
1354         fprintf(out, "\n%s", database[i][ADDRESS]);
1355         
1356         if (database[i][CITY])
1357                 fprintf(out, "\n%s", database[i][CITY]);
1358                 
1359         if (database[i][STATE] || database[i][ZIP]) {
1360                 fputc('\n', out);
1361                 
1362                 if(database[i][STATE]) {
1363                         fprintf(out, "%s", database[i][STATE]);
1364                         if(database[i][ZIP])
1365                                 fputc(' ', out);
1366                 }
1367
1368                 if(database[i][ZIP])
1369                         fprintf(out, "%s", database[i][ZIP]);
1370         }
1371
1372         if (database[i][COUNTRY])
1373                 fprintf(out, "\n%s", database[i][COUNTRY]);
1374 }
1375
1376
1377 static void
1378 text_write_address_uk(FILE *out, int i) {
1379         int j;
1380
1381         for (j = ADDRESS; j <= COUNTRY; j++)
1382                 if (database[i][j])
1383                         fprintf(out, "\n%s", database[i][j]);
1384 }
1385
1386 static void
1387 text_write_address_eu(FILE *out, int i) {
1388         fprintf(out, "\n%s", database[i][ADDRESS]);
1389         
1390         if (database[i][ZIP] || database[i][CITY]) {
1391                 fputc('\n', out);
1392
1393                 if(database[i][ZIP]) {
1394                         fprintf(out, "%s", database[i][ZIP]);
1395                         if(database[i][CITY])
1396                                 fputc(' ', out);
1397                 }
1398
1399                 if(database[i][CITY])
1400                         fprintf(out, "%s", database[i][CITY]);
1401         }
1402         
1403         if (database[i][STATE])
1404                 fprintf(out, "\n%s", database[i][STATE]);
1405
1406         if (database[i][COUNTRY])
1407                 fprintf(out, "\n%s", database[i][COUNTRY]);
1408 }
1409
1410 static int
1411 text_export_database(FILE * out, struct db_enumerator e)
1412 {
1413         char emails[MAX_EMAILS][MAX_EMAIL_LEN];
1414         int j;
1415         char *realname = get_real_name();
1416         char *style = options_get_str("address_style");
1417
1418         fprintf(out,
1419                 "-----------------------------------------\n%s's address book\n"
1420                 "-----------------------------------------\n\n\n",
1421                 realname);
1422         free(realname);
1423
1424         db_enumerate_items(e) {
1425                 fprintf(out,
1426                         "-----------------------------------------\n\n");
1427                 fprintf(out, "%s", database[e.item][NAME]);
1428                 if (database[e.item][NICK])
1429                         fprintf(out, "\n(%s)", database[e.item][NICK]);
1430                 fprintf(out, "\n");
1431
1432                 if (*database[e.item][EMAIL]) {
1433                         fprintf(out, "\n");
1434                         split_emailstr(e.item, emails);
1435                         for (j = 0; j < MAX_EMAILS; j++)
1436                                 if (*emails[j])
1437                                         fprintf(out, "%s\n", emails[j]);
1438                 }
1439                 /* Print address */
1440                 if (database[e.item][ADDRESS]) {
1441                         if (!safe_strcmp(style, "us"))  /* US like */
1442                                 text_write_address_us(out, e.item);
1443                         else if (!safe_strcmp(style, "uk"))     /* UK like */
1444                                 text_write_address_uk(out, e.item);
1445                         else    /* EU like */
1446                                 text_write_address_eu(out, e.item);
1447
1448                         fprintf(out, "\n");
1449                 }
1450
1451                 if ((database[e.item][PHONE]) ||
1452                         (database[e.item][WORKPHONE]) ||
1453                         (database[e.item][FAX]) ||
1454                         (database[e.item][MOBILEPHONE])) {
1455                         fprintf(out, "\n");
1456                         for (j = PHONE; j <= MOBILEPHONE; j++)
1457                                 if (database[e.item][j])
1458                                         fprintf(out, "%s: %s\n",
1459                                                 abook_fields[j].name,
1460                                                 database[e.item][j]);
1461                 }
1462
1463                 if (database[e.item][URL])
1464                         fprintf(out, "\n%s\n", database[e.item][URL]);
1465                 if (database[e.item][NOTES])
1466                         fprintf(out, "\n%s\n", database[e.item][NOTES]);
1467
1468                 fprintf(out, "\n");
1469         }
1470
1471         fprintf(out, "-----------------------------------------\n");
1472
1473         return 0;
1474 }
1475
1476 /*
1477  * end of printable export filter
1478  */
1479
1480 /*
1481  * elm alias export filter
1482  */
1483
1484 static int
1485 elm_alias_export(FILE *out, struct db_enumerator e)
1486 {
1487         char email[MAX_EMAIL_LEN];
1488         char *alias = NULL;
1489
1490         db_enumerate_items(e) {
1491                 alias = mutt_alias_genalias(e.item);
1492                 get_first_email(email, e.item);
1493                 fprintf(out, "%s = %s = %s\n",
1494                                 alias,
1495                                 database[e.item][NAME],
1496                                 email);
1497                 my_free(alias);
1498         }
1499
1500         return 0;
1501 }
1502
1503 /*
1504  * end of elm alias export filter
1505  */
1506
1507
1508 /*
1509  * Spruce export filter
1510  */
1511
1512 static int
1513 spruce_export_database (FILE *out, struct db_enumerator e)
1514 {
1515         char email[MAX_EMAIL_LEN];
1516
1517         fprintf (out, "# This is a generated file made by abook for the Spruce e-mail client.\n\n");
1518
1519         db_enumerate_items(e) {
1520                 if(strcmp (safe_str(database[e.item][EMAIL]), "")) {
1521                         get_first_email(email, e.item);
1522                         fprintf(out, "# Address %d\nName: %s\nEmail: %s\nMemo: %s\n\n",
1523                                         e.item,
1524                                         database[e.item][NAME],
1525                                         email,
1526                                         safe_str(database[e.item][NOTES])
1527                                         );
1528                 }
1529         }
1530
1531         fprintf (out, "# End of address book file.\n");
1532
1533         return 0;
1534 }
1535
1536 /*
1537  * end of Spruce export filter
1538  */
1539