CLI/config: migrate notmuch_config_open to new config

notmuch_config_open will be preserved in the medium term for use by
the commands that are manipulating the config file directly (config
and setup)
This commit is contained in:
David Bremner 2021-02-14 09:32:41 -04:00
parent 3787fe6c84
commit b76da87d29
7 changed files with 106 additions and 290 deletions

View file

@ -598,7 +598,7 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key)
case NOTMUCH_CONFIG_EXCLUDE_TAGS: case NOTMUCH_CONFIG_EXCLUDE_TAGS:
return ""; return "";
case NOTMUCH_CONFIG_NEW_TAGS: case NOTMUCH_CONFIG_NEW_TAGS:
return "inbox;unread"; return "unread;inbox";
case NOTMUCH_CONFIG_SYNC_MAILDIR_FLAGS: case NOTMUCH_CONFIG_SYNC_MAILDIR_FLAGS:
return "true"; return "true";
case NOTMUCH_CONFIG_USER_NAME: case NOTMUCH_CONFIG_USER_NAME:
@ -615,9 +615,10 @@ _notmuch_config_default (notmuch_database_t *notmuch, notmuch_config_key_t key)
else else
email = _get_email_from_passwd_file (notmuch); email = _get_email_from_passwd_file (notmuch);
return email; return email;
case NOTMUCH_CONFIG_NEW_IGNORE:
return "";
case NOTMUCH_CONFIG_HOOK_DIR: case NOTMUCH_CONFIG_HOOK_DIR:
case NOTMUCH_CONFIG_BACKUP_DIR: case NOTMUCH_CONFIG_BACKUP_DIR:
case NOTMUCH_CONFIG_NEW_IGNORE:
case NOTMUCH_CONFIG_OTHER_EMAIL: case NOTMUCH_CONFIG_OTHER_EMAIL:
return NULL; return NULL;
default: default:

View file

@ -276,7 +276,7 @@ typedef enum {
} notmuch_command_mode_t; } notmuch_command_mode_t;
notmuch_config_t * notmuch_config_t *
notmuch_config_open (void *ctx, notmuch_config_open (notmuch_database_t *notmuch,
const char *filename, const char *filename,
notmuch_command_mode_t config_mode); notmuch_command_mode_t config_mode);

View file

@ -31,87 +31,88 @@ static const char toplevel_config_comment[] =
"\n" "\n"
" For more information about notmuch, see https://notmuchmail.org"; " For more information about notmuch, see https://notmuchmail.org";
static const char database_config_comment[] = struct config_group {
" Database configuration\n" const char *group_name;
"\n" const char *comment;
" The only value supported here is 'path' which should be the top-level\n" } group_comment_table [] = {
" directory where your mail currently exists and to where mail will be\n" {
" delivered in the future. Files should be individual email messages.\n" "database",
" Notmuch will store its database within a sub-directory of the path\n" " Database configuration\n"
" configured here named \".notmuch\".\n"; "\n"
" The only value supported here is 'path' which should be the top-level\n"
static const char new_config_comment[] = " directory where your mail currently exists and to where mail will be\n"
" Configuration for \"notmuch new\"\n" " delivered in the future. Files should be individual email messages.\n"
"\n" " Notmuch will store its database within a sub-directory of the path\n"
" The following options are supported here:\n" " configured here named \".notmuch\".\n"
"\n" },
"\ttags A list (separated by ';') of the tags that will be\n" {
"\t added to all messages incorporated by \"notmuch new\".\n" "user",
"\n" " User configuration\n"
"\tignore A list (separated by ';') of file and directory names\n" "\n"
"\t that will not be searched for messages by \"notmuch new\".\n" " Here is where you can let notmuch know how you would like to be\n"
"\n" " addressed. Valid settings are\n"
"\t NOTE: *Every* file/directory that goes by one of those\n" "\n"
"\t names will be ignored, independent of its depth/location\n" "\tname Your full name.\n"
"\t in the mail store.\n"; "\tprimary_email Your primary email address.\n"
"\tother_email A list (separated by ';') of other email addresses\n"
static const char user_config_comment[] = "\t at which you receive email.\n"
" User configuration\n" "\n"
"\n" " Notmuch will use the various email addresses configured here when\n"
" Here is where you can let notmuch know how you would like to be\n" " formatting replies. It will avoid including your own addresses in the\n"
" addressed. Valid settings are\n" " recipient list of replies, and will set the From address based on the\n"
"\n" " address to which the original email was addressed.\n"
"\tname Your full name.\n" },
"\tprimary_email Your primary email address.\n" {
"\tother_email A list (separated by ';') of other email addresses\n" "new",
"\t at which you receive email.\n" " Configuration for \"notmuch new\"\n"
"\n" "\n"
" Notmuch will use the various email addresses configured here when\n" " The following options are supported here:\n"
" formatting replies. It will avoid including your own addresses in the\n" "\n"
" recipient list of replies, and will set the From address based on the\n" "\ttags A list (separated by ';') of the tags that will be\n"
" address to which the original email was addressed.\n"; "\t added to all messages incorporated by \"notmuch new\".\n"
"\n"
static const char maildir_config_comment[] = "\tignore A list (separated by ';') of file and directory names\n"
" Maildir compatibility configuration\n" "\t that will not be searched for messages by \"notmuch new\".\n"
"\n" "\n"
" The following option is supported here:\n" "\t NOTE: *Every* file/directory that goes by one of those\n"
"\n" "\t names will be ignored, independent of its depth/location\n"
"\tsynchronize_flags Valid values are true and false.\n" "\t in the mail store.\n"
"\n" },
"\tIf true, then the following maildir flags (in message filenames)\n" {
"\twill be synchronized with the corresponding notmuch tags:\n" "search",
"\n" " Search configuration\n"
"\t\tFlag Tag\n" "\n"
"\t\t---- -------\n" " The following option is supported here:\n"
"\t\tD draft\n" "\n"
"\t\tF flagged\n" "\texclude_tags\n"
"\t\tP passed\n" "\t\tA ;-separated list of tags that will be excluded from\n"
"\t\tR replied\n" "\t\tsearch results by default. Using an excluded tag in a\n"
"\t\tS unread (added when 'S' flag is not present)\n" "\t\tquery will override that exclusion.\n"
"\n" },
"\tThe \"notmuch new\" command will notice flag changes in filenames\n" {
"\tand update tags, while the \"notmuch tag\" and \"notmuch restore\"\n" "maildir",
"\tcommands will notice tag changes and update flags in filenames\n"; " Maildir compatibility configuration\n"
"\n"
static const char search_config_comment[] = " The following option is supported here:\n"
" Search configuration\n" "\n"
"\n" "\tsynchronize_flags Valid values are true and false.\n"
" The following option is supported here:\n" "\n"
"\n" "\tIf true, then the following maildir flags (in message filenames)\n"
"\texclude_tags\n" "\twill be synchronized with the corresponding notmuch tags:\n"
"\t\tA ;-separated list of tags that will be excluded from\n" "\n"
"\t\tsearch results by default. Using an excluded tag in a\n" "\t\tFlag Tag\n"
"\t\tquery will override that exclusion.\n"; "\t\t---- -------\n"
"\t\tD draft\n"
static const char crypto_config_comment[] = "\t\tF flagged\n"
" Cryptography related configuration\n" "\t\tP passed\n"
"\n" "\t\tR replied\n"
" The following old option is now ignored:\n" "\t\tS unread (added when 'S' flag is not present)\n"
"\n" "\n"
"\tgpgpath\n" "\tThe \"notmuch new\" command will notice flag changes in filenames\n"
"\t\tThis option was used by older builds of notmuch to choose\n" "\tand update tags, while the \"notmuch tag\" and \"notmuch restore\"\n"
"\t\tthe version of gpg to use.\n" "\tcommands will notice tag changes and update flags in filenames\n"
"\t\tSetting $PATH is a better approach.\n"; },
};
struct _notmuch_config { struct _notmuch_config {
char *filename; char *filename;
@ -141,69 +142,6 @@ notmuch_config_destructor (notmuch_config_t *config)
return 0; return 0;
} }
static char *
get_name_from_passwd_file (void *ctx)
{
long pw_buf_size;
char *pw_buf;
struct passwd passwd, *ignored;
char *name;
int e;
pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX);
if (pw_buf_size == -1) pw_buf_size = 64;
pw_buf = talloc_size (ctx, pw_buf_size);
while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
pw_buf_size, &ignored)) == ERANGE) {
pw_buf_size = pw_buf_size * 2;
pw_buf = talloc_zero_size (ctx, pw_buf_size);
}
if (e == 0) {
char *comma = strchr (passwd.pw_gecos, ',');
if (comma)
name = talloc_strndup (ctx, passwd.pw_gecos,
comma - passwd.pw_gecos);
else
name = talloc_strdup (ctx, passwd.pw_gecos);
} else {
name = talloc_strdup (ctx, "");
}
talloc_free (pw_buf);
return name;
}
static char *
get_username_from_passwd_file (void *ctx)
{
long pw_buf_size;
char *pw_buf;
struct passwd passwd, *ignored;
char *name;
int e;
pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX);
if (pw_buf_size == -1) pw_buf_size = 64;
pw_buf = talloc_zero_size (ctx, pw_buf_size);
while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
pw_buf_size, &ignored)) == ERANGE) {
pw_buf_size = pw_buf_size * 2;
pw_buf = talloc_zero_size (ctx, pw_buf_size);
}
if (e == 0)
name = talloc_strdup (ctx, passwd.pw_name);
else
name = talloc_strdup (ctx, "");
talloc_free (pw_buf);
return name;
}
static bool static bool
get_config_from_file (notmuch_config_t *config, bool create_new) get_config_from_file (notmuch_config_t *config, bool create_new)
@ -322,21 +260,13 @@ get_config_from_file (notmuch_config_t *config, bool create_new)
* user in editing the file directly. * user in editing the file directly.
*/ */
notmuch_config_t * notmuch_config_t *
notmuch_config_open (void *ctx, notmuch_config_open (notmuch_database_t *notmuch,
const char *filename, const char *filename,
notmuch_command_mode_t config_mode) notmuch_command_mode_t config_mode)
{ {
GError *error = NULL;
size_t tmp;
char *notmuch_config_env = NULL; 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;
int file_had_crypto_group;
notmuch_config_t *config = talloc_zero (ctx, notmuch_config_t); notmuch_config_t *config = talloc_zero (notmuch, notmuch_config_t);
if (config == NULL) { if (config == NULL) {
fprintf (stderr, "Out of memory.\n"); fprintf (stderr, "Out of memory.\n");
@ -368,133 +298,20 @@ notmuch_config_open (void *ctx,
} }
} }
/* 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");
file_had_crypto_group = g_key_file_has_group (config->key_file, "crypto");
if (notmuch_config_get_database_path (config) == NULL) {
char *path = getenv ("MAILDIR");
if (path)
path = talloc_strdup (config, path);
else
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 = getenv ("NAME");
if (name)
name = talloc_strdup (config, name);
else
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 (config->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 (config->is_new) if (config->is_new)
g_key_file_set_comment (config->key_file, NULL, NULL, g_key_file_set_comment (config->key_file, NULL, NULL,
toplevel_config_comment, NULL); toplevel_config_comment, NULL);
if (! file_had_database_group) for (size_t i = 0; i < ARRAY_SIZE (group_comment_table); i++) {
g_key_file_set_comment (config->key_file, "database", NULL, const char *name = group_comment_table[i].group_name;
database_config_comment, NULL); if (! g_key_file_has_group (config->key_file, name)) {
/* Force group to exist before adding comment */
if (! file_had_new_group) g_key_file_set_value (config->key_file, name, "dummy_key", "dummy_val");
g_key_file_set_comment (config->key_file, "new", NULL, g_key_file_remove_key (config->key_file, name, "dummy_key", NULL);
new_config_comment, NULL); g_key_file_set_comment (config->key_file, name, NULL,
group_comment_table[i].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 (! file_had_crypto_group)
g_key_file_set_comment (config->key_file, "crypto", NULL,
crypto_config_comment, NULL);
return config; return config;
} }

View file

@ -588,7 +588,7 @@ main (int argc, char *argv[])
} }
if (command->mode & NOTMUCH_COMMAND_CONFIG_OPEN) { if (command->mode & NOTMUCH_COMMAND_CONFIG_OPEN) {
config = notmuch_config_open (local, config_file_name, command->mode); config = notmuch_config_open (notmuch, config_file_name, command->mode);
if (! config) { if (! config) {
ret = EXIT_FAILURE; ret = EXIT_FAILURE;
goto DONE; goto DONE;

View file

@ -57,7 +57,7 @@ foo.list=this;is another;list value;
foo.string=this is another string value foo.string=this is another string value
maildir.synchronize_flags=true maildir.synchronize_flags=true
new.ignore= new.ignore=
new.tags=unread;inbox; new.tags=unread;inbox
search.exclude_tags= search.exclude_tags=
user.name=Notmuch Test Suite user.name=Notmuch Test Suite
user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org user.other_email=test_suite_other@notmuchmail.org;test_suite@otherdomain.org

View file

@ -394,8 +394,8 @@ MAIL_DIR
MAIL_DIR/.notmuch/hooks MAIL_DIR/.notmuch/hooks
MAIL_DIR/.notmuch/backups MAIL_DIR/.notmuch/backups
inbox;unread unread;inbox
NULL
true true
USERNAME@FQDN USERNAME@FQDN
NULL NULL
@ -705,7 +705,7 @@ MAIL_DIR
MAIL_DIR/.notmuch/hooks MAIL_DIR/.notmuch/hooks
MAIL_DIR/.notmuch/backups MAIL_DIR/.notmuch/backups
foo;bar;fub foo;bar;fub
unread;inbox; unread;inbox
sekrit_junk sekrit_junk
true true
test_suite@notmuchmail.org test_suite@notmuchmail.org
@ -736,8 +736,8 @@ MAIL_DIR
MAIL_DIR/.notmuch/hooks MAIL_DIR/.notmuch/hooks
MAIL_DIR/.notmuch/backups MAIL_DIR/.notmuch/backups
inbox;unread unread;inbox
NULL
true true
USERNAME@FQDN USERNAME@FQDN
NULL NULL
@ -815,7 +815,7 @@ database.path MAIL_DIR
key with spaces value, with, spaces! key with spaces value, with, spaces!
maildir.synchronize_flags true maildir.synchronize_flags true
new.ignore sekrit_junk new.ignore sekrit_junk
new.tags unread;inbox; new.tags unread;inbox
search.exclude_tags foo;bar;fub search.exclude_tags foo;bar;fub
test.key1 testvalue1 test.key1 testvalue1
test.key2 testvalue2 test.key2 testvalue2

View file

@ -49,7 +49,6 @@ other_email=another.suite@example.com;
# #
[new] [new]
tags=foo;bar; tags=foo;bar;
ignore=
# Search configuration # Search configuration
# #
@ -85,4 +84,3 @@ exclude_tags=baz;
# commands will notice tag changes and update flags in filenames # commands will notice tag changes and update flags in filenames
# #
[maildir] [maildir]
synchronize_flags=true