2 * $Id: abook.c,v 1.60 2006/09/04 18:29:24 cduval Exp $
4 * by JH <jheinonen@users.sourceforge.net>
6 * Copyright (C) Jaakko Heinonen
21 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
39 static void init_abook();
40 static void quit_abook_sig(int i
);
41 static void set_filenames();
42 static void parse_command_line(int argc
, char **argv
);
43 static void show_usage();
44 static void mutt_query(char *str
);
45 static void init_mutt_query();
46 static void convert(char *srcformat
, char *srcfile
,
47 char *dstformat
, char *dstfile
);
48 static void add_email(int);
50 char *datafile
= NULL
;
51 static char *rcfile
= NULL
;
53 bool alternative_datafile
= FALSE
;
54 bool alternative_rcfile
= FALSE
;
62 assert(datafile
!= NULL
);
64 if( (f
= fopen(datafile
, "a")) == NULL
)
73 check_abook_directory()
78 assert(!is_ui_initialized());
80 if(alternative_datafile
)
83 dir
= strconcat(getenv("HOME"), "/" DIR_IN_HOME
, NULL
);
86 if(stat(dir
, &s
) == -1) {
92 if(mkdir(dir
, 0700) == -1) {
93 printf(_("Cannot create directory %s\n"), dir
);
98 } else if(!S_ISDIR(s
.st_mode
)) {
99 printf(_("%s is not a directory\n"), dir
);
108 xmalloc_error_handler(int err
)
111 * We don't try to save addressbook here because we don't know
112 * if it's fully loaded to memory.
114 if(is_ui_initialized())
117 fprintf(stderr
, _("Memory allocation failure: %s\n"), strerror(err
));
125 check_abook_directory();
127 if(load_opts(rcfile
) > 0) {
128 printf(_("Press enter to continue...\n"));
131 init_default_views();
133 signal(SIGTERM
, quit_abook_sig
);
140 umask(DEFAULT_UMASK
);
142 if(!datafile_writeable()) {
143 char *s
= strdup_printf(_("File %s is not writeable"), datafile
);
147 if(load_database(datafile
) || !statusline_ask_boolean(
148 _("If you continue all changes will "
149 "be lost. Do you want to continue?"), FALSE
)) {
151 /*close_database();*/
156 load_database(datafile
);
162 quit_abook(int save_db
)
165 if(opt_get_bool(BOOL_AUTOSAVE
))
167 else if(statusline_ask_boolean(_("Save database"), TRUE
))
169 } else if(!statusline_ask_boolean(_("Quit without saving"), FALSE
))
181 quit_abook_sig(int i
)
183 quit_abook(QUIT_SAVE
);
187 main(int argc
, char **argv
)
189 #if defined(HAVE_SETLOCALE) && defined(HAVE_LOCALE_H)
190 setlocale(LC_ALL
, "");
193 bindtextdomain(PACKAGE
, LOCALEDIR
);
196 xmalloc_set_error_handler(xmalloc_error_handler
);
198 prepare_database_internals();
200 parse_command_line(argc
, argv
);
206 quit_abook(QUIT_SAVE
);
224 if( (stat(getenv("HOME"), &s
)) == -1 || ! S_ISDIR(s
.st_mode
) ) {
225 fprintf(stderr
,_("%s is not a valid HOME directory\n"), getenv("HOME") );
230 datafile
= strconcat(getenv("HOME"), "/" DIR_IN_HOME
"/"
234 rcfile
= strconcat(getenv("HOME"), "/" DIR_IN_HOME
"/"
237 atexit(free_filenames
);
247 MODE_ADD_EMAIL_QUIET
,
253 change_mode(int *current
, int mode
)
255 if(*current
!= MODE_CONT
) {
256 fprintf(stderr
, _("Cannot combine options --mutt-query, "
258 "--add-email or --add-email-quiet\n"));
266 set_filename(char **var
, char *path
)
271 assert(*var
== NULL
); /* or else we probably leak memory */
272 assert(path
!= NULL
);
275 *var
= xstrdup(path
);
281 *var
= strconcat(cwd
, "/", path
, NULL
);
286 #define set_convert_var(X) do { if(mode != MODE_CONVERT) {\
287 fprintf(stderr, _("please use option --%s after --convert option\n"),\
288 long_options[option_index].name);\
295 parse_command_line(int argc
, char **argv
)
297 int mode
= MODE_CONT
;
298 char *query_string
= NULL
;
299 char *informat
= "abook",
306 int option_index
= 0;
318 static struct option long_options
[] = {
319 { "help", 0, 0, 'h' },
320 { "add-email", 0, 0, OPT_ADD_EMAIL
},
321 { "add-email-quiet", 0, 0, OPT_ADD_EMAIL_QUIET
},
322 { "datafile", 1, 0, 'f' },
323 { "mutt-query", 1, 0, OPT_MUTT_QUERY
},
324 { "config", 1, 0, 'C' },
325 { "convert", 0, 0, OPT_CONVERT
},
326 { "informat", 1, 0, OPT_INFORMAT
},
327 { "outformat", 1, 0, OPT_OUTFORMAT
},
328 { "infile", 1, 0, OPT_INFILE
},
329 { "outfile", 1, 0, OPT_OUTFILE
},
330 { "formats", 0, 0, OPT_FORMATS
},
334 c
= getopt_long(argc
, argv
, "hC:",
335 long_options
, &option_index
);
345 change_mode(&mode
, MODE_ADD_EMAIL
);
347 case OPT_ADD_EMAIL_QUIET
:
348 change_mode(&mode
, MODE_ADD_EMAIL_QUIET
);
351 set_filename(&datafile
, optarg
);
352 alternative_datafile
= TRUE
;
355 query_string
= optarg
;
356 change_mode(&mode
, MODE_QUERY
);
359 set_filename(&rcfile
, optarg
);
360 alternative_rcfile
= TRUE
;
363 change_mode(&mode
, MODE_CONVERT
);
366 set_convert_var(informat
);
369 set_convert_var(outformat
);
372 set_convert_var(infile
);
375 set_convert_var(outfile
);
386 fprintf(stderr
, _("%s: unrecognized arguments on command line\n"),
394 case MODE_ADD_EMAIL_QUIET
:
397 mutt_query(query_string
);
399 convert(informat
, infile
, outformat
, outfile
);
407 puts (PACKAGE
" v " VERSION
"\n");
408 puts (_(" -h --help show usage"));
409 puts (_(" -C --config <file> use an alternative configuration file"));
410 puts (_(" --datafile <file> use an alternative addressbook file"));
411 puts (_(" --mutt-query <string> make a query for mutt"));
412 puts (_(" --add-email "
413 "read an e-mail message from stdin and\n"
415 "add the sender to the addressbook"));
416 puts (_(" --add-email-quiet "
417 "same as --add-email but doesn't\n"
418 " require to confirm adding"));
420 puts (_(" --convert convert address book files"));
421 puts (_(" options to use with --convert:"));
422 puts (_(" --informat <format> format for input file"));
423 puts (_(" (default: abook)"));
424 puts (_(" --infile <file> source file"));
425 puts (_(" (default: stdin)"));
426 puts (_(" --outformat <format> format for output file"));
427 puts (_(" (default: text)"));
428 puts (_(" --outfile <file> destination file"));
429 puts (_(" (default: stdout)"));
430 puts (_(" --formats list available formats"));
439 quit_mutt_query(int status
)
448 muttq_print_item(FILE *file
, int item
)
450 abook_list
*emails
, *e
;
451 char *tmp
= db_email_get(item
);
453 emails
= csv_to_abook_list(tmp
);
456 for(e
= emails
; e
; e
= e
->next
) {
457 fprintf(file
, "%s\t%s\t%s\n", e
->data
, db_name_get(item
),
458 !db_fget(item
, NOTES
) ?" " :db_fget(item
, NOTES
)
460 if(!opt_get_bool(BOOL_MUTT_RETURN_ALL_EMAILS
))
463 abook_list_free(&emails
);
467 mutt_query(char *str
)
471 if( str
== NULL
|| !strcasecmp(str
, "all") ) {
472 struct db_enumerator e
= init_db_enumerator(ENUM_ALL
);
473 printf("All items\n");
474 db_enumerate_items(e
)
475 muttq_print_item(stdout
, e
.item
);
477 int search_fields
[] = {NAME
, EMAIL
, NICK
, -1};
479 if( (i
= find_item(str
, 0, search_fields
)) < 0 ) {
480 printf("Not found\n");
481 quit_mutt_query(EXIT_FAILURE
);
485 muttq_print_item(stdout
, i
);
486 i
= find_item(str
, i
+ 1, search_fields
);
490 quit_mutt_query(EXIT_SUCCESS
);
500 if( load_database(datafile
) ) {
501 printf(_("Cannot open database\n"));
502 quit_mutt_query(EXIT_FAILURE
);
509 make_mailstr(int item
)
511 char email
[MAX_EMAIL_LEN
];
513 char *name
= strdup_printf("\"%s\"", db_name_get(item
));
515 get_first_email(email
, item
);
518 strdup_printf("%s <%s>", name
, email
) :
527 print_stderr(int item
)
529 fprintf (stderr
, "%c", '\n');
531 if( is_valid_item(item
) )
532 muttq_print_item(stderr
, item
);
534 struct db_enumerator e
= init_db_enumerator(ENUM_SELECTED
);
535 db_enumerate_items(e
) {
536 muttq_print_item(stderr
, e
.item
);
543 launch_mutt(int item
)
545 char *cmd
= NULL
, *mailstr
= NULL
;
546 char *mutt_command
= opt_get_str(STR_MUTT_COMMAND
);
548 if(mutt_command
== NULL
|| !*mutt_command
)
551 if( is_valid_item(item
) )
552 mailstr
= make_mailstr(item
);
554 struct db_enumerator e
= init_db_enumerator(ENUM_SELECTED
);
556 db_enumerate_items(e
) {
559 strconcat(tmp
, ",", make_mailstr(e
.item
), NULL
):
560 strconcat(make_mailstr(e
.item
), NULL
);
565 cmd
= strconcat(mutt_command
, " \'", mailstr
, "\'", NULL
);
568 fprintf(stderr
, "cmd: %s\n", cmd
);
574 * we need to make sure that curses settings are correct
580 launch_wwwbrowser(int item
)
584 if( !is_valid_item(item
) )
587 if(db_fget(item
, URL
))
588 cmd
= strdup_printf("%s '%s'",
589 opt_get_str(STR_WWW_COMMAND
),
590 safe_str(db_fget(item
, URL
)));
600 * we need to make sure that curses settings are correct
606 abook_fopen (const char *path
, const char *mode
)
611 stat_ok
= (stat(path
, &s
) != -1);
613 if(strchr(mode
, 'r'))
614 return (stat_ok
&& S_ISREG(s
.st_mode
)) ?
615 fopen(path
, mode
) : NULL
;
617 return (stat_ok
&& S_ISDIR(s
.st_mode
)) ?
618 NULL
: fopen(path
, mode
);
622 convert(char *srcformat
, char *srcfile
, char *dstformat
, char *dstfile
)
626 if( !srcformat
|| !srcfile
|| !dstformat
|| !dstfile
) {
627 fprintf(stderr
, _("too few arguments to make conversion\n"));
628 fprintf(stderr
, _("try --help\n"));
632 if( !strcasecmp(srcformat
, dstformat
) ) {
633 printf( _("input and output formats are the same\n"
642 init_standard_fields();
644 switch(import_file(srcformat
, srcfile
)) {
647 _("input format %s not supported\n"), srcformat
);
651 fprintf(stderr
, _("cannot read file %s\n"), srcfile
);
657 switch(export_file(dstformat
, dstfile
)) {
660 _("output format %s not supported\n"),
666 _("cannot write file %s\n"), dstfile
);
677 * --add-email handling
680 static int add_email_count
= 0;
685 if(add_email_count
> 0) {
686 if(save_database() < 0) {
687 fprintf(stderr
, _("cannot open %s\n"), datafile
);
690 printf(_("%d item(s) added to %s\n"), add_email_count
, datafile
);
692 puts(_("Valid sender address not found"));
699 quit_add_email_sig(int signal
)
708 check_abook_directory();
714 * we don't actually care if loading fails or not
716 load_database(datafile
);
718 atexit(close_database
);
720 signal(SIGINT
, quit_add_email_sig
);
724 add_email_add_item(int quiet
, char *name
, char *email
)
728 if(opt_get_bool(BOOL_ADD_EMAIL_PREVENT_DUPLICATES
)) {
729 int search_fields
[] = { EMAIL
, -1 };
730 if(find_item(email
, 0, search_fields
) >= 0) {
732 printf(_("Address %s already in addressbook\n"),
739 FILE *in
= fopen("/dev/tty", "r");
742 fprintf(stderr
, _("cannot open /dev/tty\n"
743 "you may want to use --add-email-quiet\n"));
748 printf(_("Add \"%s <%s>\" to %s? (%c/%c)\n"),
752 *S_("keybinding for yes|y"),
753 *S_("keybinding for no|n"));
754 c
= tolower(getc(in
));
755 if(c
== *S_("keybinding for no|n")) {
759 } while(c
!= *S_("keybinding for yes|y"));
763 item
= item_create();
764 item_fput(item
, NAME
, xstrdup(name
));
765 item_fput(item
, EMAIL
, xstrdup(email
));
766 add_item2database(item
);
776 char *name
= NULL
, *email
= NULL
;
779 if( (fstat(fileno(stdin
), &s
)) == -1 || S_ISDIR(s
.st_mode
) ) {
780 fprintf(stderr
, _("stdin is a directory or cannot stat stdin\n"));
787 line
= getaline(stdin
);
788 if(line
&& !strncasecmp("From:", line
, 5) ) {
789 getname(line
, &name
, &email
);
790 add_email_count
+= add_email_add_item(quiet
,
796 } while( !feof(stdin
) );
802 * end of --add-email handling