/* Open the named notmuch configuration file. If the filename is NULL, * the value of the environment variable $NOTMUCH_CONFIG will be used. * If $NOTMUCH_CONFIG is unset, the default configuration file * ($HOME/.notmuch-config) will be used. * * If any error occurs, (out of memory, or a permission-denied error, * etc.), this function will print a message to stderr and return * NULL. * * FILE NOT FOUND: When the specified configuration file (whether from * 'filename' or the $NOTMUCH_CONFIG environment variable) does not * exist, the behavior of this function depends on the 'is_new_ret' * variable. * * If is_new_ret is NULL, then a "file not found" message will be * printed to stderr and NULL will be returned. * If is_new_ret is non-NULL then a default configuration will be * returned and *is_new_ret will be set to 1 on return so that * the caller can recognize this case. * * These default configuration settings are determined as * follows: * * database_path: $HOME/mail * * user_name: From /etc/passwd * * user_primary_mail: $EMAIL variable if set, otherwise * constructed from the username and * hostname of the current machine. * * user_other_email: Not set. * * The default configuration also contains comments to guide the * user in editing the file directly. */ notmuch_config_t * notmuch_config_open (void *ctx, const char *filename, notmuch_bool_t *is_new_ret) { GError *error = NULL; int is_new = 0; size_t tmp; char *notmuch_config_env = NULL; int file_had_database_group; int file_had_new_group; int file_had_user_group; int file_had_maildir_group; int file_had_search_group; if (is_new_ret) *is_new_ret = 0; notmuch_config_t *config = talloc (ctx, notmuch_config_t); if (config == NULL) { fprintf (stderr, "Out of memory.\n"); return NULL; } talloc_set_destructor (config, notmuch_config_destructor); if (filename) { config->filename = talloc_strdup (config, filename); } else if ((notmuch_config_env = getenv ("NOTMUCH_CONFIG"))) { config->filename = talloc_strdup (config, notmuch_config_env); } else { config->filename = talloc_asprintf (config, "%s/.notmuch-config", getenv ("HOME")); } config->key_file = g_key_file_new (); config->database_path = NULL; config->user_name = NULL; config->user_primary_email = NULL; config->user_other_email = NULL; config->user_other_email_length = 0; config->new_tags = NULL; config->new_tags_length = 0; config->new_ignore = NULL; config->new_ignore_length = 0; config->maildir_synchronize_flags = TRUE; config->search_exclude_tags = NULL; config->search_exclude_tags_length = 0; if (! g_key_file_load_from_file (config->key_file, config->filename, G_KEY_FILE_KEEP_COMMENTS, &error)) { /* If the caller passed a non-NULL value for is_new_ret, then * the caller is prepared for a default configuration file in * the case of FILE NOT FOUND. Otherwise, any read failure is * an error. */ if (is_new_ret && error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT) { g_error_free (error); is_new = 1; } else { fprintf (stderr, "Error reading configuration file %s: %s\n", config->filename, error->message); talloc_free (config); g_error_free (error); return NULL; } } /* Whenever we know of configuration sections that don't appear in * the configuration file, we add some comments to help the user * understand what can be done. * * It would be convenient to just add those comments now, but * apparently g_key_file will clear any comments when keys are * added later that create the groups. So we have to check for the * groups now, but add the comments only after setting all of our * values. */ file_had_database_group = g_key_file_has_group (config->key_file, "database"); file_had_new_group = g_key_file_has_group (config->key_file, "new"); file_had_user_group = g_key_file_has_group (config->key_file, "user"); file_had_maildir_group = g_key_file_has_group (config->key_file, "maildir"); file_had_search_group = g_key_file_has_group (config->key_file, "search"); if (notmuch_config_get_database_path (config) == NULL) { char *path = talloc_asprintf (config, "%s/mail", getenv ("HOME")); notmuch_config_set_database_path (config, path); talloc_free (path); } if (notmuch_config_get_user_name (config) == NULL) { char *name = get_name_from_passwd_file (config); notmuch_config_set_user_name (config, name); talloc_free (name); } if (notmuch_config_get_user_primary_email (config) == NULL) { char *email = getenv ("EMAIL"); if (email) { notmuch_config_set_user_primary_email (config, email); } else { char hostname[256]; struct hostent *hostent; const char *domainname; char *username = get_username_from_passwd_file (config); gethostname (hostname, 256); hostname[255] = '\0'; hostent = gethostbyname (hostname); if (hostent && (domainname = strchr (hostent->h_name, '.'))) domainname += 1; else domainname = "(none)"; email = talloc_asprintf (config, "%s@%s.%s", username, hostname, domainname); notmuch_config_set_user_primary_email (config, email); talloc_free (username); talloc_free (email); } } if (notmuch_config_get_new_tags (config, &tmp) == NULL) { const char *tags[] = { "unread", "inbox" }; notmuch_config_set_new_tags (config, tags, 2); } if (notmuch_config_get_new_ignore (config, &tmp) == NULL) { notmuch_config_set_new_ignore (config, NULL, 0); } if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) { if (is_new) { const char *tags[] = { "deleted", "spam" }; notmuch_config_set_search_exclude_tags (config, tags, 2); } else { notmuch_config_set_search_exclude_tags (config, NULL, 0); } } error = NULL; config->maildir_synchronize_flags = g_key_file_get_boolean (config->key_file, "maildir", "synchronize_flags", &error); if (error) { notmuch_config_set_maildir_synchronize_flags (config, TRUE); g_error_free (error); } /* Whenever we know of configuration sections that don't appear in * the configuration file, we add some comments to help the user * understand what can be done. */ if (is_new) { g_key_file_set_comment (config->key_file, NULL, NULL, toplevel_config_comment, NULL); } if (! file_had_database_group) { g_key_file_set_comment (config->key_file, "database", NULL, database_config_comment, NULL); } if (! file_had_new_group) { g_key_file_set_comment (config->key_file, "new", NULL, new_config_comment, NULL); } if (! file_had_user_group) { g_key_file_set_comment (config->key_file, "user", NULL, user_config_comment, NULL); } if (! file_had_maildir_group) { g_key_file_set_comment (config->key_file, "maildir", NULL, maildir_config_comment, NULL); } if (! file_had_search_group) { g_key_file_set_comment (config->key_file, "search", NULL, search_config_comment, NULL); } if (is_new_ret) *is_new_ret = is_new; return config; }
int notmuch_setup_command (notmuch_config_t *config, unused (int argc), unused (char *argv[])) { char *response = NULL; size_t response_size = 0; const char **old_other_emails; size_t old_other_emails_len; GPtrArray *other_emails; unsigned int i; const char **new_tags; size_t new_tags_len; const char **search_exclude_tags; size_t search_exclude_tags_len; #define prompt(format, ...) \ do { \ printf (format, ##__VA_ARGS__); \ fflush (stdout); \ if (getline (&response, &response_size, stdin) < 0) { \ printf ("Exiting.\n"); \ exit (EXIT_FAILURE); \ } \ chomp_newline (response); \ } while (0) if (notmuch_config_is_new (config)) welcome_message_pre_setup (); prompt ("Your full name [%s]: ", notmuch_config_get_user_name (config)); if (strlen (response)) notmuch_config_set_user_name (config, response); prompt ("Your primary email address [%s]: ", notmuch_config_get_user_primary_email (config)); if (strlen (response)) notmuch_config_set_user_primary_email (config, response); other_emails = g_ptr_array_new (); old_other_emails = notmuch_config_get_user_other_email (config, &old_other_emails_len); for (i = 0; i < old_other_emails_len; i++) { prompt ("Additional email address [%s]: ", old_other_emails[i]); if (strlen (response)) g_ptr_array_add (other_emails, talloc_strdup (config, response)); else g_ptr_array_add (other_emails, talloc_strdup (config, old_other_emails[i])); } do { prompt ("Additional email address [Press 'Enter' if none]: "); if (strlen (response)) g_ptr_array_add (other_emails, talloc_strdup (config, response)); } while (strlen (response)); if (other_emails->len) notmuch_config_set_user_other_email (config, (const char **) other_emails->pdata, other_emails->len); g_ptr_array_free (other_emails, TRUE); prompt ("Top-level directory of your email archive [%s]: ", notmuch_config_get_database_path (config)); if (strlen (response)) { const char *absolute_path; absolute_path = make_path_absolute (config, response); notmuch_config_set_database_path (config, absolute_path); } new_tags = notmuch_config_get_new_tags (config, &new_tags_len); printf ("Tags to apply to all new messages (separated by spaces) ["); print_tag_list (new_tags, new_tags_len); prompt ("]: "); if (strlen (response)) { GPtrArray *tags = parse_tag_list (config, response); notmuch_config_set_new_tags (config, (const char **) tags->pdata, tags->len); g_ptr_array_free (tags, TRUE); } search_exclude_tags = notmuch_config_get_search_exclude_tags (config, &search_exclude_tags_len); printf ("Tags to exclude when searching messages (separated by spaces) ["); print_tag_list (search_exclude_tags, search_exclude_tags_len); prompt ("]: "); if (strlen (response)) { GPtrArray *tags = parse_tag_list (config, response); notmuch_config_set_search_exclude_tags (config, (const char **) tags->pdata, tags->len); g_ptr_array_free (tags, TRUE); } if (notmuch_config_save (config)) return EXIT_FAILURE; if (notmuch_config_is_new (config)) welcome_message_post_setup (); return EXIT_SUCCESS; }
static int _notmuch_search_prepare (search_context_t *ctx, notmuch_config_t *config, int argc, char *argv[]) { char *query_str; unsigned int i; char *status_string = NULL; switch (ctx->format_sel) { case NOTMUCH_FORMAT_TEXT: ctx->format = sprinter_text_create (config, stdout); break; case NOTMUCH_FORMAT_TEXT0: if (ctx->output == OUTPUT_SUMMARY) { fprintf (stderr, "Error: --format=text0 is not compatible with --output=summary.\n"); return EXIT_FAILURE; } ctx->format = sprinter_text0_create (config, stdout); break; case NOTMUCH_FORMAT_JSON: ctx->format = sprinter_json_create (config, stdout); break; case NOTMUCH_FORMAT_SEXP: ctx->format = sprinter_sexp_create (config, stdout); break; default: /* this should never happen */ INTERNAL_ERROR("no output format selected"); } notmuch_exit_if_unsupported_format (); if (notmuch_database_open_verbose ( notmuch_config_get_database_path (config), NOTMUCH_DATABASE_MODE_READ_ONLY, &ctx->notmuch, &status_string)) { if (status_string) { fputs (status_string, stderr); free (status_string); } return EXIT_FAILURE; } notmuch_exit_if_unmatched_db_uuid (ctx->notmuch); query_str = query_string_from_args (ctx->notmuch, argc, argv); if (query_str == NULL) { fprintf (stderr, "Out of memory.\n"); return EXIT_FAILURE; } if (*query_str == '\0') { fprintf (stderr, "Error: notmuch search requires at least one search term.\n"); return EXIT_FAILURE; } ctx->query = notmuch_query_create (ctx->notmuch, query_str); if (ctx->query == NULL) { fprintf (stderr, "Out of memory\n"); return EXIT_FAILURE; } notmuch_query_set_sort (ctx->query, ctx->sort); if (ctx->exclude == NOTMUCH_EXCLUDE_FLAG && ctx->output != OUTPUT_SUMMARY) { /* If we are not doing summary output there is nowhere to * print the excluded flag so fall back on including the * excluded messages. */ fprintf (stderr, "Warning: this output format cannot flag excluded messages.\n"); ctx->exclude = NOTMUCH_EXCLUDE_FALSE; } if (ctx->exclude != NOTMUCH_EXCLUDE_FALSE) { const char **search_exclude_tags; size_t search_exclude_tags_length; search_exclude_tags = notmuch_config_get_search_exclude_tags (config, &search_exclude_tags_length); for (i = 0; i < search_exclude_tags_length; i++) notmuch_query_add_tag_exclude (ctx->query, search_exclude_tags[i]); notmuch_query_set_omit_excluded (ctx->query, ctx->exclude); } return 0; }