4 * by JH <jheinonen@users.sourceforge.net>
6 * Copyright (C) Jaakko Heinonen
19 #if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE)
34 static void init_abook();
35 static void quit_abook_sig(int i);
36 static void set_filenames();
37 static void parse_command_line(int argc, char **argv);
38 static void show_usage();
39 static void mutt_query(char *str);
40 static void init_mutt_query();
41 static void convert(char *srcformat, char *srcfile,
42 char *dstformat, char *dstfile);
43 static void add_email(int);
45 char *datafile = NULL;
48 bool alternative_datafile = FALSE;
49 bool alternative_rcfile = FALSE;
56 assert(datafile != NULL);
58 if( (f = fopen(datafile, "a")) == NULL)
67 check_abook_directory()
72 assert(!is_ui_initialized());
74 if(alternative_datafile)
77 dir = strconcat(getenv("HOME"), "/" DIR_IN_HOME, NULL);
80 if(stat(dir, &s) == -1) {
86 if(mkdir(dir, 0700) == -1) {
87 printf("Cannot create directory %s\n", dir);
92 } else if(!S_ISDIR(s.st_mode)) {
93 printf("%s is not a directory\n", dir);
105 check_abook_directory();
109 signal(SIGKILL, quit_abook_sig);
110 signal(SIGTERM, quit_abook_sig);
115 umask(DEFAULT_UMASK);
117 if(!datafile_writeable()) {
118 char *s = mkstr("File %s is not writeable", datafile);
122 if(load_database(datafile) || !statusline_ask_boolean(
123 "If you continue all changes will "
124 "be lost. Do you want to continue?", FALSE)) {
126 /*close_database();*/
131 load_database(datafile);
139 if( opt_get_bool(BOOL_AUTOSAVE) )
141 else if( statusline_ask_boolean("Save database", TRUE) )
153 quit_abook_sig(int i)
159 main(int argc, char **argv)
161 #if defined(HAVE_SETLOCALE) && defined(HAVE_LOCALE_H)
162 setlocale(LC_ALL, "" );
165 parse_command_line(argc, argv);
189 if( (stat(getenv("HOME"), &s)) == -1 || ! S_ISDIR(s.st_mode) ) {
190 fprintf(stderr,"%s is not a valid HOME directory\n", getenv("HOME") );
195 datafile = strconcat(getenv("HOME"), "/" DIR_IN_HOME "/"
199 rcfile = strconcat(getenv("HOME"), "/" DIR_IN_HOME "/"
202 atexit(free_filenames);
212 MODE_ADD_EMAIL_QUIET,
218 change_mode(int *current, int mode)
220 if(*current != MODE_CONT) {
221 fprintf(stderr, "Cannot combine options --mutt-query, "
223 "--add-email or --add-email-quiet\n");
231 set_filename(char **var, char *path)
236 assert(*var == NULL); /* or else we probably leak memory */
237 assert(path != NULL);
246 *var = strconcat(cwd, "/", path, NULL);
251 #define set_convert_var(X) do { if(mode != MODE_CONVERT) {\
252 fprintf(stderr, "please use option --%s after --convert option\n",\
253 long_options[option_index].name);\
260 parse_command_line(int argc, char **argv)
262 int mode = MODE_CONT;
263 char *query_string = NULL;
264 char *informat = "abook",
271 int option_index = 0;
283 static struct option long_options[] = {
284 { "help", 0, 0, 'h' },
285 { "add-email", 0, 0, OPT_ADD_EMAIL },
286 { "add-email-quiet", 0, 0, OPT_ADD_EMAIL_QUIET },
287 { "datafile", 1, 0, 'f' },
288 { "mutt-query", 1, 0, OPT_MUTT_QUERY },
289 { "config", 1, 0, 'C' },
290 { "convert", 0, 0, OPT_CONVERT },
291 { "informat", 1, 0, OPT_INFORMAT },
292 { "outformat", 1, 0, OPT_OUTFORMAT },
293 { "infile", 1, 0, OPT_INFILE },
294 { "outfile", 1, 0, OPT_OUTFILE },
295 { "formats", 0, 0, OPT_FORMATS },
299 c = getopt_long(argc, argv, "hC:",
300 long_options, &option_index);
310 change_mode(&mode, MODE_ADD_EMAIL);
312 case OPT_ADD_EMAIL_QUIET:
313 change_mode(&mode, MODE_ADD_EMAIL_QUIET);
316 set_filename(&datafile, optarg);
317 alternative_datafile = TRUE;
320 query_string = optarg;
321 change_mode(&mode, MODE_QUERY);
324 set_filename(&rcfile, optarg);
325 alternative_rcfile = TRUE;
328 change_mode(&mode, MODE_CONVERT);
331 set_convert_var(informat);
334 set_convert_var(outformat);
337 set_convert_var(infile);
340 set_convert_var(outfile);
351 fprintf(stderr, "%s: unrecognized arguments on command line\n",
359 case MODE_ADD_EMAIL_QUIET:
362 mutt_query(query_string);
364 convert(informat, infile, outformat, outfile);
372 puts (PACKAGE " v " VERSION "\n");
373 puts (" -h --help show usage");
374 puts (" -C --config <file> use an alternative configuration file");
375 puts (" --datafile <file> use an alternative addressbook file");
376 puts (" --mutt-query <string> make a query for mutt");
377 puts (" --add-email "
378 "read an e-mail message from stdin and\n"
380 "add the sender to the addressbook");
381 puts (" --add-email-quiet "
382 "same as --add-email but doesn't\n"
385 puts (" --convert convert address book files");
386 puts (" options to use with --convert:");
387 puts (" --informat <format> format for input file");
388 puts (" (default: abook)");
389 puts (" --infile <file> source file");
390 puts (" (default: stdin)");
391 puts (" --outformat <format> format for output file");
392 puts (" (default: text)");
393 puts (" --outfile <file> destination file");
394 puts (" (default: stdout)");
395 puts (" --formats list available formats");
402 extern list_item *database;
405 quit_mutt_query(int status)
414 muttq_print_item(FILE *file, int item)
416 char emails[MAX_EMAILS][MAX_EMAIL_LEN];
419 split_emailstr(item, emails);
421 for(i = 0; i < (opt_get_bool(BOOL_MUTT_RETURN_ALL_EMAILS) ?
422 MAX_EMAILS : 1) ; i++)
424 fprintf(file, "%s\t%s\t%s\n", emails[i],
425 database[item][NAME],
426 database[item][NOTES] == NULL ? " " :
427 database[item][NOTES]
432 mutt_query(char *str)
436 if( str == NULL || !strcasecmp(str, "all") ) {
437 struct db_enumerator e = init_db_enumerator(ENUM_ALL);
438 printf("All items\n");
439 db_enumerate_items(e)
440 muttq_print_item(stdout, e.item);
442 int search_fields[] = {NAME, EMAIL, NICK, -1};
444 if( (i = find_item(str, 0, search_fields)) < 0 ) {
445 printf("Not found\n");
450 muttq_print_item(stdout, i);
451 i = find_item(str, i+1, search_fields);
465 if( load_database(datafile) ) {
466 printf("Cannot open database\n");
474 make_mailstr(int item)
476 char email[MAX_EMAIL_LEN];
478 char *name = mkstr("\"%s\"", database[item][NAME]);
480 get_first_email(email, item);
482 ret = *database[item][EMAIL] ?
483 mkstr("%s <%s>", name, email) :
492 print_stderr(int item)
494 fprintf (stderr, "%c", '\n');
496 if( is_valid_item(item) )
497 muttq_print_item(stderr, item);
499 struct db_enumerator e = init_db_enumerator(ENUM_SELECTED);
500 db_enumerate_items(e) {
501 muttq_print_item(stderr, e.item);
508 launch_mutt(int item)
510 char *cmd = NULL, *mailstr = NULL;
511 char *mutt_command = opt_get_str(STR_MUTT_COMMAND);
513 if(mutt_command == NULL || !*mutt_command)
516 if( is_valid_item(item) )
517 mailstr = make_mailstr(item);
519 struct db_enumerator e = init_db_enumerator(ENUM_SELECTED);
521 db_enumerate_items(e) {
524 strconcat(tmp, ",", make_mailstr(e.item), NULL):
525 strconcat(make_mailstr(e.item), NULL);
530 cmd = strconcat(mutt_command, " \'", mailstr,
534 fprintf(stderr, "cmd: %s\n", cmd);
540 * we need to make sure that curses settings are correct
546 launch_wwwbrowser(int item)
550 if( !is_valid_item(item) )
553 if( database[item][URL] )
554 cmd = mkstr("%s '%s'",
555 opt_get_str(STR_WWW_COMMAND),
556 safe_str(database[item][URL]));
566 * we need to make sure that curses settings are correct
572 abook_malloc(size_t size)
576 if ( (ptr = malloc(size)) == NULL ) {
577 if( is_ui_initialized() )
579 perror("malloc() failed");
587 abook_realloc(void *ptr, size_t size)
589 ptr = realloc(ptr, size);
595 if( is_ui_initialized() )
597 perror("realloc() failed");
605 abook_fopen (const char *path, const char *mode)
610 stat_ok = (stat(path, &s) != -1);
612 if(strchr(mode, 'r'))
613 return (stat_ok && S_ISREG(s.st_mode)) ?
614 fopen(path, mode) : NULL;
616 return (stat_ok && S_ISDIR(s.st_mode)) ?
617 NULL : fopen(path, mode);
621 convert(char *srcformat, char *srcfile, char *dstformat, char *dstfile)
625 if( !srcformat || !srcfile || !dstformat || !dstfile ) {
626 fprintf(stderr, "too few argumets to make conversion\n");
627 fprintf(stderr, "try --help\n");
631 if( !strcasecmp(srcformat, dstformat) ) {
632 printf( "input and output formats are the same\n"
642 switch( import_file(srcformat, srcfile) ) {
645 "input format %s not supported\n", srcformat);
649 fprintf(stderr, "cannot read file %s\n", srcfile);
655 switch( export_file(dstformat, dstfile) ) {
658 "output format %s not supported\n",
664 "cannot write file %s\n", dstfile);
675 * --add-email handling
678 static int add_email_count = 0;
683 if(add_email_count > 0) {
684 if(save_database() < 0) {
685 fprintf(stderr, "cannot open %s\n", datafile);
688 printf("%d item(s) added to %s\n", add_email_count, datafile);
690 puts("Valid sender address not found");
697 quit_add_email_sig(int signal)
706 atexit(free_filenames);
712 * we don't actually care if loading fails or not
714 load_database(datafile);
716 atexit(close_database);
718 signal(SIGINT, quit_add_email_sig);
722 add_email_add_item(int quiet, char *name, char *email)
727 FILE *in = fopen("/dev/tty", "r");
730 fprintf(stderr, "cannot open /dev/tty\n"
731 "you may want to use --add-email-quiet\n");
734 printf("Add ``%s <%s>'' to %s ? (y/n)\n",
741 if(c == 'n' || c == 'N') {
745 } while(c != 'y' && c != 'Y');
749 memset(item, 0, sizeof(item));
750 item[NAME] = strdup(name);
751 item[EMAIL] = strdup(email);
752 add_item2database(item);
761 char *name = NULL, *email = NULL;
764 if( (fstat(fileno(stdin), &s)) == -1 || S_ISDIR(s.st_mode)) {
765 fprintf(stderr, "stdin is a directory or cannot stat stdin\n");
772 line = getaline(stdin);
773 if(line && !strncasecmp("From:", line, 5) ) {
774 getname(line, &name, &email);
775 add_email_count += add_email_add_item(quiet,
781 } while( !feof(stdin) );
787 * end of --add-email handling