1 /* notmuch - Not much of an email program, (just index and search)
3 * Copyright © 2009 Carl Worth
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see https://www.gnu.org/licenses/ .
18 * Author: Carl Worth <cworth@cworth.org>
21 #include "notmuch-client.h"
27 static const char toplevel_config_comment[] =
28 " .notmuch-config - Configuration file for the notmuch mail system\n"
30 " For more information about notmuch, see https://notmuchmail.org";
32 static const char database_config_comment[] =
33 " Database configuration\n"
35 " The only value supported here is 'path' which should be the top-level\n"
36 " directory where your mail currently exists and to where mail will be\n"
37 " delivered in the future. Files should be individual email messages.\n"
38 " Notmuch will store its database within a sub-directory of the path\n"
39 " configured here named \".notmuch\".\n";
41 static const char new_config_comment[] =
42 " Configuration for \"notmuch new\"\n"
44 " The following options are supported here:\n"
46 "\ttags A list (separated by ';') of the tags that will be\n"
47 "\t added to all messages incorporated by \"notmuch new\".\n"
49 "\tignore A list (separated by ';') of file and directory names\n"
50 "\t that will not be searched for messages by \"notmuch new\".\n"
52 "\t NOTE: *Every* file/directory that goes by one of those\n"
53 "\t names will be ignored, independent of its depth/location\n"
54 "\t in the mail store.\n";
56 static const char user_config_comment[] =
57 " User configuration\n"
59 " Here is where you can let notmuch know how you would like to be\n"
60 " addressed. Valid settings are\n"
62 "\tname Your full name.\n"
63 "\tprimary_email Your primary email address.\n"
64 "\tother_email A list (separated by ';') of other email addresses\n"
65 "\t at which you receive email.\n"
67 " Notmuch will use the various email addresses configured here when\n"
68 " formatting replies. It will avoid including your own addresses in the\n"
69 " recipient list of replies, and will set the From address based on the\n"
70 " address to which the original email was addressed.\n";
72 static const char maildir_config_comment[] =
73 " Maildir compatibility configuration\n"
75 " The following option is supported here:\n"
77 "\tsynchronize_flags Valid values are true and false.\n"
79 "\tIf true, then the following maildir flags (in message filenames)\n"
80 "\twill be synchronized with the corresponding notmuch tags:\n"
88 "\t\tS unread (added when 'S' flag is not present)\n"
90 "\tThe \"notmuch new\" command will notice flag changes in filenames\n"
91 "\tand update tags, while the \"notmuch tag\" and \"notmuch restore\"\n"
92 "\tcommands will notice tag changes and update flags in filenames\n";
94 static const char search_config_comment[] =
95 " Search configuration\n"
97 " The following option is supported here:\n"
100 "\t\tA ;-separated list of tags that will be excluded from\n"
101 "\t\tsearch results by default. Using an excluded tag in a\n"
102 "\t\tquery will override that exclusion.\n";
104 static const char crypto_config_comment[] =
105 " Cryptography related configuration\n"
107 " The following old option is now ignored:\n"
110 "\t\tThis option was used by older builds of notmuch to choose\n"
111 "\t\tthe version of gpg to use.\n"
112 "\t\tSetting $PATH is a better approach.\n";
114 struct _notmuch_config {
120 char *crypto_gpg_path;
122 char *user_primary_email;
123 const char **user_other_email;
124 size_t user_other_email_length;
125 const char **new_tags;
126 size_t new_tags_length;
127 const char **new_ignore;
128 size_t new_ignore_length;
129 bool maildir_synchronize_flags;
130 const char **search_exclude_tags;
131 size_t search_exclude_tags_length;
135 notmuch_config_destructor (notmuch_config_t *config)
137 if (config->key_file)
138 g_key_file_free (config->key_file);
144 get_name_from_passwd_file (void *ctx)
148 struct passwd passwd, *ignored;
152 pw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
153 if (pw_buf_size == -1) pw_buf_size = 64;
154 pw_buf = talloc_size (ctx, pw_buf_size);
156 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
157 pw_buf_size, &ignored)) == ERANGE) {
158 pw_buf_size = pw_buf_size * 2;
159 pw_buf = talloc_zero_size(ctx, pw_buf_size);
163 char *comma = strchr (passwd.pw_gecos, ',');
165 name = talloc_strndup (ctx, passwd.pw_gecos,
166 comma - passwd.pw_gecos);
168 name = talloc_strdup (ctx, passwd.pw_gecos);
170 name = talloc_strdup (ctx, "");
173 talloc_free (pw_buf);
179 get_username_from_passwd_file (void *ctx)
183 struct passwd passwd, *ignored;
187 pw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
188 if (pw_buf_size == -1) pw_buf_size = 64;
189 pw_buf = talloc_zero_size (ctx, pw_buf_size);
191 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
192 pw_buf_size, &ignored)) == ERANGE) {
193 pw_buf_size = pw_buf_size * 2;
194 pw_buf = talloc_zero_size(ctx, pw_buf_size);
198 name = talloc_strdup (ctx, passwd.pw_name);
200 name = talloc_strdup (ctx, "");
202 talloc_free (pw_buf);
208 get_config_from_file (notmuch_config_t *config, bool create_new)
210 #define BUF_SIZE 4096
211 char *config_str = NULL;
213 int config_bufsize = BUF_SIZE;
215 GError *error = NULL;
218 FILE *fp = fopen(config->filename, "r");
220 if (errno == ENOENT) {
221 /* If create_new is true, then the caller is prepared for a
222 * default configuration file in the case of FILE NOT FOUND.
225 config->is_new = true;
228 fprintf (stderr, "Configuration file %s not found.\n"
229 "Try running 'notmuch setup' to create a configuration.\n",
233 fprintf (stderr, "Error opening config file '%s': %s\n",
234 config->filename, strerror(errno));
239 config_str = talloc_zero_array (config, char, config_bufsize);
240 if (config_str == NULL) {
241 fprintf (stderr, "Error reading '%s': Out of memory\n", config->filename);
245 while ((len = fread (config_str + config_len, 1,
246 config_bufsize - config_len, fp)) > 0) {
248 if (config_len == config_bufsize) {
249 config_bufsize += BUF_SIZE;
250 config_str = talloc_realloc (config, config_str, char, config_bufsize);
251 if (config_str == NULL) {
252 fprintf (stderr, "Error reading '%s': Failed to reallocate memory\n",
260 fprintf (stderr, "Error reading '%s': I/O error\n", config->filename);
264 if (g_key_file_load_from_data (config->key_file, config_str, config_len,
265 G_KEY_FILE_KEEP_COMMENTS, &error)) {
270 fprintf (stderr, "Error parsing config file '%s': %s\n",
271 config->filename, error->message);
273 g_error_free (error);
280 talloc_free(config_str);
285 /* Open the named notmuch configuration file. If the filename is NULL,
286 * the value of the environment variable $NOTMUCH_CONFIG will be used.
287 * If $NOTMUCH_CONFIG is unset, the default configuration file
288 * ($HOME/.notmuch-config) will be used.
290 * If any error occurs, (out of memory, or a permission-denied error,
291 * etc.), this function will print a message to stderr and return
294 * FILE NOT FOUND: When the specified configuration file (whether from
295 * 'filename' or the $NOTMUCH_CONFIG environment variable) does not
296 * exist, the behavior of this function depends on the 'is_new_ret'
299 * If is_new_ret is NULL, then a "file not found" message will be
300 * printed to stderr and NULL will be returned.
302 * If is_new_ret is non-NULL then a default configuration will be
303 * returned and *is_new_ret will be set to 1 on return so that
304 * the caller can recognize this case.
306 * These default configuration settings are determined as
309 * database_path: $MAILDIR, otherwise $HOME/mail
311 * user_name: $NAME variable if set, otherwise
312 * read from /etc/passwd
314 * user_primary_mail: $EMAIL variable if set, otherwise
315 * constructed from the username and
316 * hostname of the current machine.
318 * user_other_email: Not set.
320 * The default configuration also contains comments to guide the
321 * user in editing the file directly.
324 notmuch_config_open (void *ctx,
325 const char *filename,
326 notmuch_config_mode_t config_mode)
328 GError *error = NULL;
330 char *notmuch_config_env = NULL;
331 int file_had_database_group;
332 int file_had_new_group;
333 int file_had_user_group;
334 int file_had_maildir_group;
335 int file_had_search_group;
336 int file_had_crypto_group;
338 notmuch_config_t *config = talloc_zero (ctx, notmuch_config_t);
339 if (config == NULL) {
340 fprintf (stderr, "Out of memory.\n");
344 talloc_set_destructor (config, notmuch_config_destructor);
346 /* non-zero defaults */
347 config->maildir_synchronize_flags = true;
350 config->filename = talloc_strdup (config, filename);
351 } else if ((notmuch_config_env = getenv ("NOTMUCH_CONFIG"))) {
352 config->filename = talloc_strdup (config, notmuch_config_env);
354 config->filename = talloc_asprintf (config, "%s/.notmuch-config",
358 config->key_file = g_key_file_new ();
360 if (config_mode & NOTMUCH_CONFIG_OPEN) {
361 bool create_new = (config_mode & NOTMUCH_CONFIG_CREATE) != 0;
363 if (! get_config_from_file (config, create_new)) {
364 talloc_free (config);
369 /* Whenever we know of configuration sections that don't appear in
370 * the configuration file, we add some comments to help the user
371 * understand what can be done.
373 * It would be convenient to just add those comments now, but
374 * apparently g_key_file will clear any comments when keys are
375 * added later that create the groups. So we have to check for the
376 * groups now, but add the comments only after setting all of our
379 file_had_database_group = g_key_file_has_group (config->key_file,
381 file_had_new_group = g_key_file_has_group (config->key_file, "new");
382 file_had_user_group = g_key_file_has_group (config->key_file, "user");
383 file_had_maildir_group = g_key_file_has_group (config->key_file, "maildir");
384 file_had_search_group = g_key_file_has_group (config->key_file, "search");
385 file_had_crypto_group = g_key_file_has_group (config->key_file, "crypto");
387 if (notmuch_config_get_database_path (config) == NULL) {
388 char *path = getenv ("MAILDIR");
390 path = talloc_strdup (config, path);
392 path = talloc_asprintf (config, "%s/mail",
394 notmuch_config_set_database_path (config, path);
398 if (notmuch_config_get_user_name (config) == NULL) {
399 char *name = getenv ("NAME");
401 name = talloc_strdup (config, name);
403 name = get_name_from_passwd_file (config);
404 notmuch_config_set_user_name (config, name);
408 if (notmuch_config_get_user_primary_email (config) == NULL) {
409 char *email = getenv ("EMAIL");
411 notmuch_config_set_user_primary_email (config, email);
414 struct hostent *hostent;
415 const char *domainname;
417 char *username = get_username_from_passwd_file (config);
419 gethostname (hostname, 256);
420 hostname[255] = '\0';
422 hostent = gethostbyname (hostname);
423 if (hostent && (domainname = strchr (hostent->h_name, '.')))
426 domainname = "(none)";
428 email = talloc_asprintf (config, "%s@%s.%s",
429 username, hostname, domainname);
431 notmuch_config_set_user_primary_email (config, email);
433 talloc_free (username);
438 if (notmuch_config_get_new_tags (config, &tmp) == NULL) {
439 const char *tags[] = { "unread", "inbox" };
440 notmuch_config_set_new_tags (config, tags, 2);
443 if (notmuch_config_get_new_ignore (config, &tmp) == NULL) {
444 notmuch_config_set_new_ignore (config, NULL, 0);
447 if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) {
448 if (config->is_new) {
449 const char *tags[] = { "deleted", "spam" };
450 notmuch_config_set_search_exclude_tags (config, tags, 2);
452 notmuch_config_set_search_exclude_tags (config, NULL, 0);
457 config->maildir_synchronize_flags =
458 g_key_file_get_boolean (config->key_file,
459 "maildir", "synchronize_flags", &error);
461 notmuch_config_set_maildir_synchronize_flags (config, true);
462 g_error_free (error);
465 /* Whenever we know of configuration sections that don't appear in
466 * the configuration file, we add some comments to help the user
467 * understand what can be done. */
469 g_key_file_set_comment (config->key_file, NULL, NULL,
470 toplevel_config_comment, NULL);
472 if (! file_had_database_group)
473 g_key_file_set_comment (config->key_file, "database", NULL,
474 database_config_comment, NULL);
476 if (! file_had_new_group)
477 g_key_file_set_comment (config->key_file, "new", NULL,
478 new_config_comment, NULL);
480 if (! file_had_user_group)
481 g_key_file_set_comment (config->key_file, "user", NULL,
482 user_config_comment, NULL);
484 if (! file_had_maildir_group)
485 g_key_file_set_comment (config->key_file, "maildir", NULL,
486 maildir_config_comment, NULL);
488 if (! file_had_search_group)
489 g_key_file_set_comment (config->key_file, "search", NULL,
490 search_config_comment, NULL);
492 if (! file_had_crypto_group)
493 g_key_file_set_comment (config->key_file, "crypto", NULL,
494 crypto_config_comment, NULL);
499 /* Close the given notmuch_config_t object, freeing all resources.
501 * Note: Any changes made to the configuration are *not* saved by this
502 * function. To save changes, call notmuch_config_save before
503 * notmuch_config_close.
506 notmuch_config_close (notmuch_config_t *config)
508 talloc_free (config);
511 /* Save any changes made to the notmuch configuration.
513 * Any comments originally in the file will be preserved.
515 * Returns 0 if successful, and 1 in case of any error, (after
516 * printing a description of the error to stderr).
519 notmuch_config_save (notmuch_config_t *config)
522 char *data, *filename;
523 GError *error = NULL;
525 data = g_key_file_to_data (config->key_file, &length, NULL);
527 fprintf (stderr, "Out of memory.\n");
531 /* Try not to overwrite symlinks. */
532 filename = canonicalize_file_name (config->filename);
534 if (errno == ENOENT) {
535 filename = strdup (config->filename);
537 fprintf (stderr, "Out of memory.\n");
542 fprintf (stderr, "Error canonicalizing %s: %s\n", config->filename,
549 if (! g_file_set_contents (filename, data, length, &error)) {
550 if (strcmp (filename, config->filename) != 0) {
551 fprintf (stderr, "Error saving configuration to %s (-> %s): %s\n",
552 config->filename, filename, error->message);
554 fprintf (stderr, "Error saving configuration to %s: %s\n",
555 filename, error->message);
557 g_error_free (error);
569 notmuch_config_is_new (notmuch_config_t *config)
571 return config->is_new;
575 _config_get (notmuch_config_t *config, char **field,
576 const char *group, const char *key)
578 /* read from config file and cache value, if not cached already */
579 if (*field == NULL) {
581 value = g_key_file_get_string (config->key_file, group, key, NULL);
583 *field = talloc_strdup (config, value);
591 _config_set (notmuch_config_t *config, char **field,
592 const char *group, const char *key, const char *value)
594 g_key_file_set_string (config->key_file, group, key, value);
596 /* drop the cached value */
597 talloc_free (*field);
602 _config_get_list (notmuch_config_t *config,
603 const char *section, const char *key,
604 const char ***outlist, size_t *list_length, size_t *ret_length)
608 /* read from config file and cache value, if not cached already */
609 if (*outlist == NULL) {
611 char **inlist = g_key_file_get_string_list (config->key_file,
612 section, key, list_length, NULL);
616 *outlist = talloc_size (config, sizeof (char *) * (*list_length + 1));
618 for (i = 0; i < *list_length; i++)
619 (*outlist)[i] = talloc_strdup (*outlist, inlist[i]);
621 (*outlist)[i] = NULL;
628 *ret_length = *list_length;
634 _config_set_list (notmuch_config_t *config,
635 const char *group, const char *key,
637 size_t length, const char ***config_var )
639 g_key_file_set_string_list (config->key_file, group, key, list, length);
641 /* drop the cached value */
642 talloc_free (*config_var);
647 notmuch_config_get_database_path (notmuch_config_t *config)
649 char *db_path = (char *)_config_get (config, &config->database_path, "database", "path");
651 if (db_path && *db_path != '/') {
652 /* If the path in the configuration file begins with any
653 * character other than /, presume that it is relative to
654 * $HOME and update as appropriate.
656 char *abs_path = talloc_asprintf (config, "%s/%s", getenv ("HOME"), db_path);
657 talloc_free (db_path);
658 db_path = config->database_path = abs_path;
665 notmuch_config_set_database_path (notmuch_config_t *config,
666 const char *database_path)
668 _config_set (config, &config->database_path, "database", "path", database_path);
672 notmuch_config_get_user_name (notmuch_config_t *config)
674 return _config_get (config, &config->user_name, "user", "name");
678 notmuch_config_set_user_name (notmuch_config_t *config,
679 const char *user_name)
681 _config_set (config, &config->user_name, "user", "name", user_name);
685 notmuch_config_get_user_primary_email (notmuch_config_t *config)
687 return _config_get (config, &config->user_primary_email, "user", "primary_email");
691 notmuch_config_set_user_primary_email (notmuch_config_t *config,
692 const char *primary_email)
694 _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email);
698 notmuch_config_get_user_other_email (notmuch_config_t *config, size_t *length)
700 return _config_get_list (config, "user", "other_email",
701 &(config->user_other_email),
702 &(config->user_other_email_length), length);
706 notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
708 return _config_get_list (config, "new", "tags",
710 &(config->new_tags_length), length);
714 notmuch_config_get_new_ignore (notmuch_config_t *config, size_t *length)
716 return _config_get_list (config, "new", "ignore",
717 &(config->new_ignore),
718 &(config->new_ignore_length), length);
722 notmuch_config_set_user_other_email (notmuch_config_t *config,
726 _config_set_list (config, "user", "other_email", list, length,
727 &(config->user_other_email));
731 notmuch_config_set_new_tags (notmuch_config_t *config,
735 _config_set_list (config, "new", "tags", list, length,
736 &(config->new_tags));
740 notmuch_config_set_new_ignore (notmuch_config_t *config,
744 _config_set_list (config, "new", "ignore", list, length,
745 &(config->new_ignore));
749 notmuch_config_get_search_exclude_tags (notmuch_config_t *config, size_t *length)
751 return _config_get_list (config, "search", "exclude_tags",
752 &(config->search_exclude_tags),
753 &(config->search_exclude_tags_length), length);
757 notmuch_config_set_search_exclude_tags (notmuch_config_t *config,
761 _config_set_list (config, "search", "exclude_tags", list, length,
762 &(config->search_exclude_tags));
766 /* Given a configuration item of the form <group>.<key> return the
767 * component group and key. If any error occurs, print a message on
768 * stderr and return 1. Otherwise, return 0.
770 * Note: This function modifies the original 'item' string.
773 _item_split (char *item, char **group, char **key)
779 period = strchr (item, '.');
780 if (period == NULL || *(period+1) == '\0') {
782 "Invalid configuration name: %s\n"
783 "(Should be of the form <section>.<item>)\n", item);
793 #define BUILT_WITH_PREFIX "built_with."
795 typedef struct config_key {
799 bool (*validate)(const char *);
802 static struct config_key
803 config_key_table[] = {
804 {"index.decrypt", true, false, NULL},
805 {"index.header.", true, true, NULL},
806 {"query.", true, true, NULL},
809 static config_key_info_t *
810 _config_key_info (const char *item)
812 for (size_t i = 0; i < ARRAY_SIZE (config_key_table); i++) {
813 if (config_key_table[i].prefix &&
814 strncmp (item, config_key_table[i].name,
815 strlen(config_key_table[i].name)) == 0)
816 return config_key_table+i;
817 if (strcmp (item, config_key_table[i].name) == 0)
818 return config_key_table+i;
824 _stored_in_db (const char *item)
826 config_key_info_t *info;
827 info = _config_key_info (item);
829 return (info && info->in_db);
833 _print_db_config(notmuch_config_t *config, const char *name)
835 notmuch_database_t *notmuch;
838 if (notmuch_database_open (notmuch_config_get_database_path (config),
839 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
842 /* XXX Handle UUID mismatch? */
844 if (print_status_database ("notmuch config", notmuch,
845 notmuch_database_get_config (notmuch, name, &val)))
854 notmuch_config_command_get (notmuch_config_t *config, char *item)
856 if (strcmp(item, "database.path") == 0) {
857 printf ("%s\n", notmuch_config_get_database_path (config));
858 } else if (strcmp(item, "user.name") == 0) {
859 printf ("%s\n", notmuch_config_get_user_name (config));
860 } else if (strcmp(item, "user.primary_email") == 0) {
861 printf ("%s\n", notmuch_config_get_user_primary_email (config));
862 } else if (strcmp(item, "user.other_email") == 0) {
863 const char **other_email;
866 other_email = notmuch_config_get_user_other_email (config, &length);
867 for (i = 0; i < length; i++)
868 printf ("%s\n", other_email[i]);
869 } else if (strcmp(item, "new.tags") == 0) {
873 tags = notmuch_config_get_new_tags (config, &length);
874 for (i = 0; i < length; i++)
875 printf ("%s\n", tags[i]);
876 } else if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
878 notmuch_built_with (item + strlen (BUILT_WITH_PREFIX)) ? "true" : "false");
879 } else if (_stored_in_db (item)) {
880 return _print_db_config (config, item);
886 if (_item_split (item, &group, &key))
889 value = g_key_file_get_string_list (config->key_file,
893 fprintf (stderr, "Unknown configuration item: %s.%s\n",
898 for (i = 0; i < length; i++)
899 printf ("%s\n", value[i]);
908 _set_db_config(notmuch_config_t *config, const char *key, int argc, char **argv)
910 notmuch_database_t *notmuch;
911 const char *val = "";
914 /* XXX handle lists? */
915 fprintf (stderr, "notmuch config set: at most one value expected for %s\n", key);
923 if (notmuch_database_open (notmuch_config_get_database_path (config),
924 NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
927 /* XXX Handle UUID mismatch? */
929 if (print_status_database ("notmuch config", notmuch,
930 notmuch_database_set_config (notmuch, key, val)))
933 if (print_status_database ("notmuch config", notmuch,
934 notmuch_database_close (notmuch)))
941 notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[])
944 config_key_info_t *key_info;
946 if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
947 fprintf (stderr, "Error: read only option: %s\n", item);
951 key_info = _config_key_info (item);
952 if (key_info && key_info->validate && (! key_info->validate (item)))
955 if (key_info && key_info->in_db) {
956 return _set_db_config (config, item, argc, argv);
959 if (_item_split (item, &group, &key))
962 /* With only the name of an item, we clear it from the
963 * configuration file.
965 * With a single value, we set it as a string.
967 * With multiple values, we set them as a string list.
971 g_key_file_remove_key (config->key_file, group, key, NULL);
974 g_key_file_set_string (config->key_file, group, key, argv[0]);
977 g_key_file_set_string_list (config->key_file, group, key,
978 (const gchar **) argv, argc);
982 return notmuch_config_save (config);
987 _notmuch_config_list_built_with ()
989 printf("%scompact=%s\n",
991 notmuch_built_with ("compact") ? "true" : "false");
992 printf("%sfield_processor=%s\n",
994 notmuch_built_with ("field_processor") ? "true" : "false");
995 printf("%sretry_lock=%s\n",
997 notmuch_built_with ("retry_lock") ? "true" : "false");
1001 _list_db_config (notmuch_config_t *config)
1003 notmuch_database_t *notmuch;
1004 notmuch_config_list_t *list;
1006 if (notmuch_database_open (notmuch_config_get_database_path (config),
1007 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
1008 return EXIT_FAILURE;
1010 /* XXX Handle UUID mismatch? */
1013 if (print_status_database ("notmuch config", notmuch,
1014 notmuch_database_get_config_list (notmuch, "", &list)))
1015 return EXIT_FAILURE;
1017 for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
1018 printf("%s=%s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));
1020 notmuch_config_list_destroy (list);
1022 return EXIT_SUCCESS;
1026 notmuch_config_command_list (notmuch_config_t *config)
1029 size_t g, groups_length;
1031 groups = g_key_file_get_groups (config->key_file, &groups_length);
1035 for (g = 0; g < groups_length; g++) {
1037 size_t k, keys_length;
1039 keys = g_key_file_get_keys (config->key_file,
1040 groups[g], &keys_length, NULL);
1044 for (k = 0; k < keys_length; k++) {
1047 value = g_key_file_get_string (config->key_file,
1048 groups[g], keys[k], NULL);
1049 if (value != NULL) {
1050 printf ("%s.%s=%s\n", groups[g], keys[k], value);
1058 g_strfreev (groups);
1060 _notmuch_config_list_built_with ();
1061 return _list_db_config (config);
1065 notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])
1070 opt_index = notmuch_minimal_options ("config", argc, argv);
1072 return EXIT_FAILURE;
1074 if (notmuch_requested_db_uuid)
1075 fprintf (stderr, "Warning: ignoring --uuid=%s\n",
1076 notmuch_requested_db_uuid);
1078 /* skip at least subcommand argument */
1083 fprintf (stderr, "Error: notmuch config requires at least one argument.\n");
1084 return EXIT_FAILURE;
1087 if (strcmp (argv[0], "get") == 0) {
1089 fprintf (stderr, "Error: notmuch config get requires exactly "
1091 return EXIT_FAILURE;
1093 ret = notmuch_config_command_get (config, argv[1]);
1094 } else if (strcmp (argv[0], "set") == 0) {
1096 fprintf (stderr, "Error: notmuch config set requires at least "
1098 return EXIT_FAILURE;
1100 ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2);
1101 } else if (strcmp (argv[0], "list") == 0) {
1102 ret = notmuch_config_command_list (config);
1104 fprintf (stderr, "Unrecognized argument for notmuch config: %s\n",
1106 return EXIT_FAILURE;
1109 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
1114 notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config)
1116 return config->maildir_synchronize_flags;
1120 notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config,
1121 bool synchronize_flags)
1123 g_key_file_set_boolean (config->key_file,
1124 "maildir", "synchronize_flags", synchronize_flags);
1125 config->maildir_synchronize_flags = synchronize_flags;