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 #if (GMIME_MAJOR_VERSION < 3)
108 " The following *deprecated* option is currently supported:\n"
111 "\t\tbinary name or full path to invoke gpg.\n"
112 "\t\tNOTE: In a future build, this option will be ignored.\n"
114 " The following old option is now ignored:\n"
117 "\t\tThis option was used by older builds of notmuch to choose\n"
118 "\t\tthe version of gpg to use.\n"
120 "\t\tSetting $PATH is a better approach.\n";
122 struct _notmuch_config {
128 char *crypto_gpg_path;
130 char *user_primary_email;
131 const char **user_other_email;
132 size_t user_other_email_length;
133 const char **new_tags;
134 size_t new_tags_length;
135 const char **new_ignore;
136 size_t new_ignore_length;
137 bool maildir_synchronize_flags;
138 const char **search_exclude_tags;
139 size_t search_exclude_tags_length;
143 notmuch_config_destructor (notmuch_config_t *config)
145 if (config->key_file)
146 g_key_file_free (config->key_file);
152 get_name_from_passwd_file (void *ctx)
156 struct passwd passwd, *ignored;
160 pw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
161 if (pw_buf_size == -1) pw_buf_size = 64;
162 pw_buf = talloc_size (ctx, pw_buf_size);
164 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
165 pw_buf_size, &ignored)) == ERANGE) {
166 pw_buf_size = pw_buf_size * 2;
167 pw_buf = talloc_zero_size(ctx, pw_buf_size);
171 char *comma = strchr (passwd.pw_gecos, ',');
173 name = talloc_strndup (ctx, passwd.pw_gecos,
174 comma - passwd.pw_gecos);
176 name = talloc_strdup (ctx, passwd.pw_gecos);
178 name = talloc_strdup (ctx, "");
181 talloc_free (pw_buf);
187 get_username_from_passwd_file (void *ctx)
191 struct passwd passwd, *ignored;
195 pw_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
196 if (pw_buf_size == -1) pw_buf_size = 64;
197 pw_buf = talloc_zero_size (ctx, pw_buf_size);
199 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
200 pw_buf_size, &ignored)) == ERANGE) {
201 pw_buf_size = pw_buf_size * 2;
202 pw_buf = talloc_zero_size(ctx, pw_buf_size);
206 name = talloc_strdup (ctx, passwd.pw_name);
208 name = talloc_strdup (ctx, "");
210 talloc_free (pw_buf);
216 get_config_from_file (notmuch_config_t *config, bool create_new)
218 #define BUF_SIZE 4096
219 char *config_str = NULL;
221 int config_bufsize = BUF_SIZE;
223 GError *error = NULL;
226 FILE *fp = fopen(config->filename, "r");
228 if (errno == ENOENT) {
229 /* If create_new is true, then the caller is prepared for a
230 * default configuration file in the case of FILE NOT FOUND.
233 config->is_new = true;
236 fprintf (stderr, "Configuration file %s not found.\n"
237 "Try running 'notmuch setup' to create a configuration.\n",
241 fprintf (stderr, "Error opening config file '%s': %s\n",
242 config->filename, strerror(errno));
247 config_str = talloc_zero_array (config, char, config_bufsize);
248 if (config_str == NULL) {
249 fprintf (stderr, "Error reading '%s': Out of memory\n", config->filename);
253 while ((len = fread (config_str + config_len, 1,
254 config_bufsize - config_len, fp)) > 0) {
256 if (config_len == config_bufsize) {
257 config_bufsize += BUF_SIZE;
258 config_str = talloc_realloc (config, config_str, char, config_bufsize);
259 if (config_str == NULL) {
260 fprintf (stderr, "Error reading '%s': Failed to reallocate memory\n",
268 fprintf (stderr, "Error reading '%s': I/O error\n", config->filename);
272 if (g_key_file_load_from_data (config->key_file, config_str, config_len,
273 G_KEY_FILE_KEEP_COMMENTS, &error)) {
278 fprintf (stderr, "Error parsing config file '%s': %s\n",
279 config->filename, error->message);
281 g_error_free (error);
288 talloc_free(config_str);
293 /* Open the named notmuch configuration file. If the filename is NULL,
294 * the value of the environment variable $NOTMUCH_CONFIG will be used.
295 * If $NOTMUCH_CONFIG is unset, the default configuration file
296 * ($HOME/.notmuch-config) will be used.
298 * If any error occurs, (out of memory, or a permission-denied error,
299 * etc.), this function will print a message to stderr and return
302 * FILE NOT FOUND: When the specified configuration file (whether from
303 * 'filename' or the $NOTMUCH_CONFIG environment variable) does not
304 * exist, the behavior of this function depends on the 'is_new_ret'
307 * If is_new_ret is NULL, then a "file not found" message will be
308 * printed to stderr and NULL will be returned.
310 * If is_new_ret is non-NULL then a default configuration will be
311 * returned and *is_new_ret will be set to 1 on return so that
312 * the caller can recognize this case.
314 * These default configuration settings are determined as
317 * database_path: $MAILDIR, otherwise $HOME/mail
319 * user_name: $NAME variable if set, otherwise
320 * read from /etc/passwd
322 * user_primary_mail: $EMAIL variable if set, otherwise
323 * constructed from the username and
324 * hostname of the current machine.
326 * user_other_email: Not set.
328 * The default configuration also contains comments to guide the
329 * user in editing the file directly.
332 notmuch_config_open (void *ctx,
333 const char *filename,
334 notmuch_config_mode_t config_mode)
336 GError *error = NULL;
338 char *notmuch_config_env = NULL;
339 int file_had_database_group;
340 int file_had_new_group;
341 int file_had_user_group;
342 int file_had_maildir_group;
343 int file_had_search_group;
344 int file_had_crypto_group;
346 notmuch_config_t *config = talloc_zero (ctx, notmuch_config_t);
347 if (config == NULL) {
348 fprintf (stderr, "Out of memory.\n");
352 talloc_set_destructor (config, notmuch_config_destructor);
354 /* non-zero defaults */
355 config->maildir_synchronize_flags = true;
358 config->filename = talloc_strdup (config, filename);
359 } else if ((notmuch_config_env = getenv ("NOTMUCH_CONFIG"))) {
360 config->filename = talloc_strdup (config, notmuch_config_env);
362 config->filename = talloc_asprintf (config, "%s/.notmuch-config",
366 config->key_file = g_key_file_new ();
368 if (config_mode & NOTMUCH_CONFIG_OPEN) {
369 bool create_new = (config_mode & NOTMUCH_CONFIG_CREATE) != 0;
371 if (! get_config_from_file (config, create_new)) {
372 talloc_free (config);
377 /* Whenever we know of configuration sections that don't appear in
378 * the configuration file, we add some comments to help the user
379 * understand what can be done.
381 * It would be convenient to just add those comments now, but
382 * apparently g_key_file will clear any comments when keys are
383 * added later that create the groups. So we have to check for the
384 * groups now, but add the comments only after setting all of our
387 file_had_database_group = g_key_file_has_group (config->key_file,
389 file_had_new_group = g_key_file_has_group (config->key_file, "new");
390 file_had_user_group = g_key_file_has_group (config->key_file, "user");
391 file_had_maildir_group = g_key_file_has_group (config->key_file, "maildir");
392 file_had_search_group = g_key_file_has_group (config->key_file, "search");
393 file_had_crypto_group = g_key_file_has_group (config->key_file, "crypto");
395 if (notmuch_config_get_database_path (config) == NULL) {
396 char *path = getenv ("MAILDIR");
398 path = talloc_strdup (config, path);
400 path = talloc_asprintf (config, "%s/mail",
402 notmuch_config_set_database_path (config, path);
406 if (notmuch_config_get_user_name (config) == NULL) {
407 char *name = getenv ("NAME");
409 name = talloc_strdup (config, name);
411 name = get_name_from_passwd_file (config);
412 notmuch_config_set_user_name (config, name);
416 if (notmuch_config_get_user_primary_email (config) == NULL) {
417 char *email = getenv ("EMAIL");
419 notmuch_config_set_user_primary_email (config, email);
422 struct hostent *hostent;
423 const char *domainname;
425 char *username = get_username_from_passwd_file (config);
427 gethostname (hostname, 256);
428 hostname[255] = '\0';
430 hostent = gethostbyname (hostname);
431 if (hostent && (domainname = strchr (hostent->h_name, '.')))
434 domainname = "(none)";
436 email = talloc_asprintf (config, "%s@%s.%s",
437 username, hostname, domainname);
439 notmuch_config_set_user_primary_email (config, email);
441 talloc_free (username);
446 if (notmuch_config_get_new_tags (config, &tmp) == NULL) {
447 const char *tags[] = { "unread", "inbox" };
448 notmuch_config_set_new_tags (config, tags, 2);
451 if (notmuch_config_get_new_ignore (config, &tmp) == NULL) {
452 notmuch_config_set_new_ignore (config, NULL, 0);
455 if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) {
456 if (config->is_new) {
457 const char *tags[] = { "deleted", "spam" };
458 notmuch_config_set_search_exclude_tags (config, tags, 2);
460 notmuch_config_set_search_exclude_tags (config, NULL, 0);
465 config->maildir_synchronize_flags =
466 g_key_file_get_boolean (config->key_file,
467 "maildir", "synchronize_flags", &error);
469 notmuch_config_set_maildir_synchronize_flags (config, true);
470 g_error_free (error);
473 #if (GMIME_MAJOR_VERSION < 3)
474 if (notmuch_config_get_crypto_gpg_path (config) == NULL) {
475 notmuch_config_set_crypto_gpg_path (config, "gpg");
479 /* Whenever we know of configuration sections that don't appear in
480 * the configuration file, we add some comments to help the user
481 * understand what can be done. */
483 g_key_file_set_comment (config->key_file, NULL, NULL,
484 toplevel_config_comment, NULL);
486 if (! file_had_database_group)
487 g_key_file_set_comment (config->key_file, "database", NULL,
488 database_config_comment, NULL);
490 if (! file_had_new_group)
491 g_key_file_set_comment (config->key_file, "new", NULL,
492 new_config_comment, NULL);
494 if (! file_had_user_group)
495 g_key_file_set_comment (config->key_file, "user", NULL,
496 user_config_comment, NULL);
498 if (! file_had_maildir_group)
499 g_key_file_set_comment (config->key_file, "maildir", NULL,
500 maildir_config_comment, NULL);
502 if (! file_had_search_group)
503 g_key_file_set_comment (config->key_file, "search", NULL,
504 search_config_comment, NULL);
506 if (! file_had_crypto_group)
507 g_key_file_set_comment (config->key_file, "crypto", NULL,
508 crypto_config_comment, NULL);
513 /* Close the given notmuch_config_t object, freeing all resources.
515 * Note: Any changes made to the configuration are *not* saved by this
516 * function. To save changes, call notmuch_config_save before
517 * notmuch_config_close.
520 notmuch_config_close (notmuch_config_t *config)
522 talloc_free (config);
525 /* Save any changes made to the notmuch configuration.
527 * Any comments originally in the file will be preserved.
529 * Returns 0 if successful, and 1 in case of any error, (after
530 * printing a description of the error to stderr).
533 notmuch_config_save (notmuch_config_t *config)
536 char *data, *filename;
537 GError *error = NULL;
539 data = g_key_file_to_data (config->key_file, &length, NULL);
541 fprintf (stderr, "Out of memory.\n");
545 /* Try not to overwrite symlinks. */
546 filename = canonicalize_file_name (config->filename);
548 if (errno == ENOENT) {
549 filename = strdup (config->filename);
551 fprintf (stderr, "Out of memory.\n");
556 fprintf (stderr, "Error canonicalizing %s: %s\n", config->filename,
563 if (! g_file_set_contents (filename, data, length, &error)) {
564 if (strcmp (filename, config->filename) != 0) {
565 fprintf (stderr, "Error saving configuration to %s (-> %s): %s\n",
566 config->filename, filename, error->message);
568 fprintf (stderr, "Error saving configuration to %s: %s\n",
569 filename, error->message);
571 g_error_free (error);
583 notmuch_config_is_new (notmuch_config_t *config)
585 return config->is_new;
589 _config_get (notmuch_config_t *config, char **field,
590 const char *group, const char *key)
592 /* read from config file and cache value, if not cached already */
593 if (*field == NULL) {
595 value = g_key_file_get_string (config->key_file, group, key, NULL);
597 *field = talloc_strdup (config, value);
605 _config_set (notmuch_config_t *config, char **field,
606 const char *group, const char *key, const char *value)
608 g_key_file_set_string (config->key_file, group, key, value);
610 /* drop the cached value */
611 talloc_free (*field);
616 _config_get_list (notmuch_config_t *config,
617 const char *section, const char *key,
618 const char ***outlist, size_t *list_length, size_t *ret_length)
622 /* read from config file and cache value, if not cached already */
623 if (*outlist == NULL) {
625 char **inlist = g_key_file_get_string_list (config->key_file,
626 section, key, list_length, NULL);
630 *outlist = talloc_size (config, sizeof (char *) * (*list_length + 1));
632 for (i = 0; i < *list_length; i++)
633 (*outlist)[i] = talloc_strdup (*outlist, inlist[i]);
635 (*outlist)[i] = NULL;
642 *ret_length = *list_length;
648 _config_set_list (notmuch_config_t *config,
649 const char *group, const char *key,
651 size_t length, const char ***config_var )
653 g_key_file_set_string_list (config->key_file, group, key, list, length);
655 /* drop the cached value */
656 talloc_free (*config_var);
661 notmuch_config_get_database_path (notmuch_config_t *config)
663 char *db_path = (char *)_config_get (config, &config->database_path, "database", "path");
665 if (db_path && *db_path != '/') {
666 /* If the path in the configuration file begins with any
667 * character other than /, presume that it is relative to
668 * $HOME and update as appropriate.
670 char *abs_path = talloc_asprintf (config, "%s/%s", getenv ("HOME"), db_path);
671 talloc_free (db_path);
672 db_path = config->database_path = abs_path;
679 notmuch_config_set_database_path (notmuch_config_t *config,
680 const char *database_path)
682 _config_set (config, &config->database_path, "database", "path", database_path);
686 notmuch_config_get_user_name (notmuch_config_t *config)
688 return _config_get (config, &config->user_name, "user", "name");
692 notmuch_config_set_user_name (notmuch_config_t *config,
693 const char *user_name)
695 _config_set (config, &config->user_name, "user", "name", user_name);
699 notmuch_config_get_user_primary_email (notmuch_config_t *config)
701 return _config_get (config, &config->user_primary_email, "user", "primary_email");
705 notmuch_config_set_user_primary_email (notmuch_config_t *config,
706 const char *primary_email)
708 _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email);
712 notmuch_config_get_user_other_email (notmuch_config_t *config, size_t *length)
714 return _config_get_list (config, "user", "other_email",
715 &(config->user_other_email),
716 &(config->user_other_email_length), length);
720 notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
722 return _config_get_list (config, "new", "tags",
724 &(config->new_tags_length), length);
728 notmuch_config_get_new_ignore (notmuch_config_t *config, size_t *length)
730 return _config_get_list (config, "new", "ignore",
731 &(config->new_ignore),
732 &(config->new_ignore_length), length);
736 notmuch_config_set_user_other_email (notmuch_config_t *config,
740 _config_set_list (config, "user", "other_email", list, length,
741 &(config->user_other_email));
745 notmuch_config_set_new_tags (notmuch_config_t *config,
749 _config_set_list (config, "new", "tags", list, length,
750 &(config->new_tags));
754 notmuch_config_set_new_ignore (notmuch_config_t *config,
758 _config_set_list (config, "new", "ignore", list, length,
759 &(config->new_ignore));
763 notmuch_config_get_search_exclude_tags (notmuch_config_t *config, size_t *length)
765 return _config_get_list (config, "search", "exclude_tags",
766 &(config->search_exclude_tags),
767 &(config->search_exclude_tags_length), length);
771 notmuch_config_set_search_exclude_tags (notmuch_config_t *config,
775 _config_set_list (config, "search", "exclude_tags", list, length,
776 &(config->search_exclude_tags));
779 #if (GMIME_MAJOR_VERSION < 3)
781 notmuch_config_get_crypto_gpg_path (notmuch_config_t *config)
783 return _config_get (config, &config->crypto_gpg_path, "crypto", "gpg_path");
787 notmuch_config_set_crypto_gpg_path (notmuch_config_t *config,
788 const char *gpg_path)
790 _config_set (config, &config->crypto_gpg_path, "crypto", "gpg_path", gpg_path);
795 /* Given a configuration item of the form <group>.<key> return the
796 * component group and key. If any error occurs, print a message on
797 * stderr and return 1. Otherwise, return 0.
799 * Note: This function modifies the original 'item' string.
802 _item_split (char *item, char **group, char **key)
808 period = strchr (item, '.');
809 if (period == NULL || *(period+1) == '\0') {
811 "Invalid configuration name: %s\n"
812 "(Should be of the form <section>.<item>)\n", item);
822 #define BUILT_WITH_PREFIX "built_with."
825 _stored_in_db (const char *item)
827 const char * db_configs[] = {
830 if (STRNCMP_LITERAL (item, "query.") == 0)
832 for (size_t i = 0; i < ARRAY_SIZE (db_configs); i++)
833 if (strcmp (item, db_configs[i]) == 0)
839 _print_db_config(notmuch_config_t *config, const char *name)
841 notmuch_database_t *notmuch;
844 if (notmuch_database_open (notmuch_config_get_database_path (config),
845 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
848 /* XXX Handle UUID mismatch? */
850 if (print_status_database ("notmuch config", notmuch,
851 notmuch_database_get_config (notmuch, name, &val)))
860 notmuch_config_command_get (notmuch_config_t *config, char *item)
862 if (strcmp(item, "database.path") == 0) {
863 printf ("%s\n", notmuch_config_get_database_path (config));
864 } else if (strcmp(item, "user.name") == 0) {
865 printf ("%s\n", notmuch_config_get_user_name (config));
866 } else if (strcmp(item, "user.primary_email") == 0) {
867 printf ("%s\n", notmuch_config_get_user_primary_email (config));
868 } else if (strcmp(item, "user.other_email") == 0) {
869 const char **other_email;
872 other_email = notmuch_config_get_user_other_email (config, &length);
873 for (i = 0; i < length; i++)
874 printf ("%s\n", other_email[i]);
875 } else if (strcmp(item, "new.tags") == 0) {
879 tags = notmuch_config_get_new_tags (config, &length);
880 for (i = 0; i < length; i++)
881 printf ("%s\n", tags[i]);
882 } else if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
884 notmuch_built_with (item + strlen (BUILT_WITH_PREFIX)) ? "true" : "false");
885 } else if (_stored_in_db (item)) {
886 return _print_db_config (config, item);
892 if (_item_split (item, &group, &key))
895 value = g_key_file_get_string_list (config->key_file,
899 fprintf (stderr, "Unknown configuration item: %s.%s\n",
904 for (i = 0; i < length; i++)
905 printf ("%s\n", value[i]);
914 _set_db_config(notmuch_config_t *config, const char *key, int argc, char **argv)
916 notmuch_database_t *notmuch;
917 const char *val = "";
920 /* XXX handle lists? */
921 fprintf (stderr, "notmuch config set: at most one value expected for %s\n", key);
929 if (notmuch_database_open (notmuch_config_get_database_path (config),
930 NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
933 /* XXX Handle UUID mismatch? */
935 if (print_status_database ("notmuch config", notmuch,
936 notmuch_database_set_config (notmuch, key, val)))
939 if (print_status_database ("notmuch config", notmuch,
940 notmuch_database_close (notmuch)))
947 notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[])
951 if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
952 fprintf (stderr, "Error: read only option: %s\n", item);
956 if (_stored_in_db (item)) {
957 return _set_db_config (config, item, argc, argv);
960 if (_item_split (item, &group, &key))
963 /* With only the name of an item, we clear it from the
964 * configuration file.
966 * With a single value, we set it as a string.
968 * With multiple values, we set them as a string list.
972 g_key_file_remove_key (config->key_file, group, key, NULL);
975 g_key_file_set_string (config->key_file, group, key, argv[0]);
978 g_key_file_set_string_list (config->key_file, group, key,
979 (const gchar **) argv, argc);
983 return notmuch_config_save (config);
988 _notmuch_config_list_built_with ()
990 printf("%scompact=%s\n",
992 notmuch_built_with ("compact") ? "true" : "false");
993 printf("%sfield_processor=%s\n",
995 notmuch_built_with ("field_processor") ? "true" : "false");
996 printf("%sretry_lock=%s\n",
998 notmuch_built_with ("retry_lock") ? "true" : "false");
1002 _list_db_config (notmuch_config_t *config)
1004 notmuch_database_t *notmuch;
1005 notmuch_config_list_t *list;
1007 if (notmuch_database_open (notmuch_config_get_database_path (config),
1008 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
1009 return EXIT_FAILURE;
1011 /* XXX Handle UUID mismatch? */
1014 if (print_status_database ("notmuch config", notmuch,
1015 notmuch_database_get_config_list (notmuch, "", &list)))
1016 return EXIT_FAILURE;
1018 for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
1019 printf("%s=%s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));
1021 notmuch_config_list_destroy (list);
1023 return EXIT_SUCCESS;
1027 notmuch_config_command_list (notmuch_config_t *config)
1030 size_t g, groups_length;
1032 groups = g_key_file_get_groups (config->key_file, &groups_length);
1036 for (g = 0; g < groups_length; g++) {
1038 size_t k, keys_length;
1040 keys = g_key_file_get_keys (config->key_file,
1041 groups[g], &keys_length, NULL);
1045 for (k = 0; k < keys_length; k++) {
1048 value = g_key_file_get_string (config->key_file,
1049 groups[g], keys[k], NULL);
1050 if (value != NULL) {
1051 printf ("%s.%s=%s\n", groups[g], keys[k], value);
1059 g_strfreev (groups);
1061 _notmuch_config_list_built_with ();
1062 return _list_db_config (config);
1066 notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])
1071 opt_index = notmuch_minimal_options ("config", argc, argv);
1073 return EXIT_FAILURE;
1075 if (notmuch_requested_db_uuid)
1076 fprintf (stderr, "Warning: ignoring --uuid=%s\n",
1077 notmuch_requested_db_uuid);
1079 /* skip at least subcommand argument */
1084 fprintf (stderr, "Error: notmuch config requires at least one argument.\n");
1085 return EXIT_FAILURE;
1088 if (strcmp (argv[0], "get") == 0) {
1090 fprintf (stderr, "Error: notmuch config get requires exactly "
1092 return EXIT_FAILURE;
1094 ret = notmuch_config_command_get (config, argv[1]);
1095 } else if (strcmp (argv[0], "set") == 0) {
1097 fprintf (stderr, "Error: notmuch config set requires at least "
1099 return EXIT_FAILURE;
1101 ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2);
1102 } else if (strcmp (argv[0], "list") == 0) {
1103 ret = notmuch_config_command_list (config);
1105 fprintf (stderr, "Unrecognized argument for notmuch config: %s\n",
1107 return EXIT_FAILURE;
1110 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
1115 notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config)
1117 return config->maildir_synchronize_flags;
1121 notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config,
1122 bool synchronize_flags)
1124 g_key_file_set_boolean (config->key_file,
1125 "maildir", "synchronize_flags", synchronize_flags);
1126 config->maildir_synchronize_flags = synchronize_flags;