4 * by JH <jheinonen@users.sourceforge.net>
6 * Copyright (C) Jaakko Heinonen
20 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
36 static void init_abook();
37 static void quit_abook_sig(int i);
38 static void set_filenames();
39 static void parse_command_line(int argc, char **argv);
40 static void show_usage();
41 static void mutt_query(char *str);
42 static void init_mutt_query();
43 static void convert(char *srcformat, char *srcfile,
44 char *dstformat, char *dstfile);
45 static void add_email(int);
47 char *datafile = NULL;
48 static char *rcfile = NULL;
50 bool alternative_datafile = FALSE;
51 bool alternative_rcfile = FALSE;
58 assert(datafile != NULL);
60 if( (f = fopen(datafile, "a")) == NULL)
69 check_abook_directory()
74 assert(!is_ui_initialized());
76 if(alternative_datafile)
79 dir = strconcat(getenv("HOME"), "/" DIR_IN_HOME, NULL);
82 if(stat(dir, &s) == -1) {
88 if(mkdir(dir, 0700) == -1) {
89 printf("Cannot create directory %s\n", dir);
94 } else if(!S_ISDIR(s.st_mode)) {
95 printf("%s is not a directory\n", dir);
104 xmalloc_error_handler(int err)
107 * We don't try to save addressbook here because we don't know
108 * if it's fully loaded to memory.
110 if(is_ui_initialized())
113 fprintf(stderr, "Memory allocation failure: %s\n", strerror(err));
121 check_abook_directory();
123 if(load_opts(rcfile) > 0) {
124 printf("Press enter to continue...\n");
128 signal(SIGTERM, quit_abook_sig);
133 umask(DEFAULT_UMASK);
135 if(!datafile_writeable()) {
136 char *s = mkstr("File %s is not writeable", datafile);
140 if(load_database(datafile) || !statusline_ask_boolean(
141 "If you continue all changes will "
142 "be lost. Do you want to continue?", FALSE)) {
144 /*close_database();*/
149 load_database(datafile);
155 quit_abook(int save_db)
158 if(opt_get_bool(BOOL_AUTOSAVE))
160 else if(statusline_ask_boolean("Save database", TRUE))
162 } else if(!statusline_ask_boolean("Quit without saving", FALSE))
174 quit_abook_sig(int i)
176 quit_abook(QUIT_SAVE);
180 main(int argc, char **argv)
182 #if defined(HAVE_SETLOCALE) && defined(HAVE_LOCALE_H)
183 setlocale(LC_ALL, "");
185 xmalloc_set_error_handler(xmalloc_error_handler);
187 parse_command_line(argc, argv);
193 quit_abook(QUIT_SAVE);
211 if( (stat(getenv("HOME"), &s)) == -1 || ! S_ISDIR(s.st_mode) ) {
212 fprintf(stderr,"%s is not a valid HOME directory\n", getenv("HOME") );
217 datafile = strconcat(getenv("HOME"), "/" DIR_IN_HOME "/"
221 rcfile = strconcat(getenv("HOME"), "/" DIR_IN_HOME "/"
224 atexit(free_filenames);
234 MODE_ADD_EMAIL_QUIET,
240 change_mode(int *current, int mode)
242 if(*current != MODE_CONT) {
243 fprintf(stderr, "Cannot combine options --mutt-query, "
245 "--add-email or --add-email-quiet\n");
253 set_filename(char **var, char *path)
258 assert(*var == NULL); /* or else we probably leak memory */
259 assert(path != NULL);
262 *var = xstrdup(path);
268 *var = strconcat(cwd, "/", path, NULL);
273 #define set_convert_var(X) do { if(mode != MODE_CONVERT) {\
274 fprintf(stderr, "please use option --%s after --convert option\n",\
275 long_options[option_index].name);\
282 parse_command_line(int argc, char **argv)
284 int mode = MODE_CONT;
285 char *query_string = NULL;
286 char *informat = "abook",
293 int option_index = 0;
305 static struct option long_options[] = {
306 { "help", 0, 0, 'h' },
307 { "add-email", 0, 0, OPT_ADD_EMAIL },
308 { "add-email-quiet", 0, 0, OPT_ADD_EMAIL_QUIET },
309 { "datafile", 1, 0, 'f' },
310 { "mutt-query", 1, 0, OPT_MUTT_QUERY },
311 { "config", 1, 0, 'C' },
312 { "convert", 0, 0, OPT_CONVERT },
313 { "informat", 1, 0, OPT_INFORMAT },
314 { "outformat", 1, 0, OPT_OUTFORMAT },
315 { "infile", 1, 0, OPT_INFILE },
316 { "outfile", 1, 0, OPT_OUTFILE },
317 { "formats", 0, 0, OPT_FORMATS },
321 c = getopt_long(argc, argv, "hC:",
322 long_options, &option_index);
332 change_mode(&mode, MODE_ADD_EMAIL);
334 case OPT_ADD_EMAIL_QUIET:
335 change_mode(&mode, MODE_ADD_EMAIL_QUIET);
338 set_filename(&datafile, optarg);
339 alternative_datafile = TRUE;
342 query_string = optarg;
343 change_mode(&mode, MODE_QUERY);
346 set_filename(&rcfile, optarg);
347 alternative_rcfile = TRUE;
350 change_mode(&mode, MODE_CONVERT);
353 set_convert_var(informat);
356 set_convert_var(outformat);
359 set_convert_var(infile);
362 set_convert_var(outfile);
373 fprintf(stderr, "%s: unrecognized arguments on command line\n",
381 case MODE_ADD_EMAIL_QUIET:
384 mutt_query(query_string);
386 convert(informat, infile, outformat, outfile);
394 puts (PACKAGE " v " VERSION "\n");
395 puts (" -h --help show usage");
396 puts (" -C --config <file> use an alternative configuration file");
397 puts (" --datafile <file> use an alternative addressbook file");
398 puts (" --mutt-query <string> make a query for mutt");
399 puts (" --add-email "
400 "read an e-mail message from stdin and\n"
402 "add the sender to the addressbook");
403 puts (" --add-email-quiet "
404 "same as --add-email but doesn't\n"
407 puts (" --convert convert address book files");
408 puts (" options to use with --convert:");
409 puts (" --informat <format> format for input file");
410 puts (" (default: abook)");
411 puts (" --infile <file> source file");
412 puts (" (default: stdin)");
413 puts (" --outformat <format> format for output file");
414 puts (" (default: text)");
415 puts (" --outfile <file> destination file");
416 puts (" (default: stdout)");
417 puts (" --formats list available formats");
424 extern list_item *database;
427 quit_mutt_query(int status)
436 muttq_print_item(FILE *file, int item)
438 char emails[MAX_EMAILS][MAX_EMAIL_LEN];
441 split_emailstr(item, emails);
443 for(i = 0; i < (opt_get_bool(BOOL_MUTT_RETURN_ALL_EMAILS) ?
444 MAX_EMAILS : 1) ; i++)
446 fprintf(file, "%s\t%s\t%s\n", emails[i],
447 database[item][NAME],
448 database[item][NOTES] == NULL ? " " :
449 database[item][NOTES]
454 mutt_query(char *str)
458 if( str == NULL || !strcasecmp(str, "all") ) {
459 struct db_enumerator e = init_db_enumerator(ENUM_ALL);
460 printf("All items\n");
461 db_enumerate_items(e)
462 muttq_print_item(stdout, e.item);
464 int search_fields[] = {NAME, EMAIL, NICK, -1};
466 if( (i = find_item(str, 0, search_fields)) < 0 ) {
467 printf("Not found\n");
468 quit_mutt_query(EXIT_FAILURE);
472 muttq_print_item(stdout, i);
473 i = find_item(str, i + 1, search_fields);
477 quit_mutt_query(EXIT_SUCCESS);
487 if( load_database(datafile) ) {
488 printf("Cannot open database\n");
489 quit_mutt_query(EXIT_FAILURE);
496 make_mailstr(int item)
498 char email[MAX_EMAIL_LEN];
500 char *name = mkstr("\"%s\"", database[item][NAME]);
502 get_first_email(email, item);
504 ret = *database[item][EMAIL] ?
505 mkstr("%s <%s>", name, email) :
514 print_stderr(int item)
516 fprintf (stderr, "%c", '\n');
518 if( is_valid_item(item) )
519 muttq_print_item(stderr, item);
521 struct db_enumerator e = init_db_enumerator(ENUM_SELECTED);
522 db_enumerate_items(e) {
523 muttq_print_item(stderr, e.item);
530 launch_mutt(int item)
532 char *cmd = NULL, *mailstr = NULL;
533 char *mutt_command = opt_get_str(STR_MUTT_COMMAND);
535 if(mutt_command == NULL || !*mutt_command)
538 if( is_valid_item(item) )
539 mailstr = make_mailstr(item);
541 struct db_enumerator e = init_db_enumerator(ENUM_SELECTED);
543 db_enumerate_items(e) {
546 strconcat(tmp, ",", make_mailstr(e.item), NULL):
547 strconcat(make_mailstr(e.item), NULL);
552 cmd = strconcat(mutt_command, " \'", mailstr, "\'", NULL);
555 fprintf(stderr, "cmd: %s\n", cmd);
561 * we need to make sure that curses settings are correct
567 launch_wwwbrowser(int item)
571 if( !is_valid_item(item) )
574 if( database[item][URL] )
575 cmd = mkstr("%s '%s'",
576 opt_get_str(STR_WWW_COMMAND),
577 safe_str(database[item][URL]));
587 * we need to make sure that curses settings are correct
593 abook_fopen (const char *path, const char *mode)
598 stat_ok = (stat(path, &s) != -1);
600 if(strchr(mode, 'r'))
601 return (stat_ok && S_ISREG(s.st_mode)) ?
602 fopen(path, mode) : NULL;
604 return (stat_ok && S_ISDIR(s.st_mode)) ?
605 NULL : fopen(path, mode);
609 convert(char *srcformat, char *srcfile, char *dstformat, char *dstfile)
613 if( !srcformat || !srcfile || !dstformat || !dstfile ) {
614 fprintf(stderr, "too few argumets to make conversion\n");
615 fprintf(stderr, "try --help\n");
619 if( !strcasecmp(srcformat, dstformat) ) {
620 printf( "input and output formats are the same\n"
630 switch(import_file(srcformat, srcfile)) {
633 "input format %s not supported\n", srcformat);
637 fprintf(stderr, "cannot read file %s\n", srcfile);
643 switch(export_file(dstformat, dstfile)) {
646 "output format %s not supported\n",
652 "cannot write file %s\n", dstfile);
663 * --add-email handling
666 static int add_email_count = 0;
671 if(add_email_count > 0) {
672 if(save_database() < 0) {
673 fprintf(stderr, "cannot open %s\n", datafile);
676 printf("%d item(s) added to %s\n", add_email_count, datafile);
678 puts("Valid sender address not found");
685 quit_add_email_sig(int signal)
694 check_abook_directory();
700 * we don't actually care if loading fails or not
702 load_database(datafile);
704 atexit(close_database);
706 signal(SIGINT, quit_add_email_sig);
710 add_email_add_item(int quiet, char *name, char *email)
714 if(opt_get_bool(BOOL_ADD_EMAIL_PREVENT_DUPLICATES)) {
715 int search_fields[] = { EMAIL, -1 };
716 if(find_item(email, 0, search_fields) >= 0) {
718 printf("Address %s already in addressbook\n",
725 FILE *in = fopen("/dev/tty", "r");
728 fprintf(stderr, "cannot open /dev/tty\n"
729 "you may want to use --add-email-quiet\n");
734 printf("Add ``%s <%s>'' to %s ? (y/n)\n",
739 if(c == 'n' || c == 'N') {
743 } while(c != 'y' && c != 'Y');
747 memset(item, 0, sizeof(item));
748 item[NAME] = xstrdup(name);
749 item[EMAIL] = xstrdup(email);
750 add_item2database(item);
759 char *name = NULL, *email = NULL;
762 if( (fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode) ) {
763 fprintf(stderr, "stdin is a directory or cannot stat stdin\n");
770 line = getaline(stdin);
771 if(line && !strncasecmp("From:", line, 5) ) {
772 getname(line, &name, &email);
773 add_email_count += add_email_add_item(quiet,
779 } while( !feof(stdin) );
785 * end of --add-email handling