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 #include "unicode-util.h"
29 static const char toplevel_config_comment[] =
30 " .notmuch-config - Configuration file for the notmuch mail system\n"
32 " For more information about notmuch, see https://notmuchmail.org";
34 static const char database_config_comment[] =
35 " Database configuration\n"
37 " The only value supported here is 'path' which should be the top-level\n"
38 " directory where your mail currently exists and to where mail will be\n"
39 " delivered in the future. Files should be individual email messages.\n"
40 " Notmuch will store its database within a sub-directory of the path\n"
41 " configured here named \".notmuch\".\n";
43 static const char new_config_comment[] =
44 " Configuration for \"notmuch new\"\n"
46 " The following options are supported here:\n"
48 "\ttags A list (separated by ';') of the tags that will be\n"
49 "\t added to all messages incorporated by \"notmuch new\".\n"
51 "\tignore A list (separated by ';') of file and directory names\n"
52 "\t that will not be searched for messages by \"notmuch new\".\n"
54 "\t NOTE: *Every* file/directory that goes by one of those\n"
55 "\t names will be ignored, independent of its depth/location\n"
56 "\t in the mail store.\n";
58 static const char user_config_comment[] =
59 " User configuration\n"
61 " Here is where you can let notmuch know how you would like to be\n"
62 " addressed. Valid settings are\n"
64 "\tname Your full name.\n"
65 "\tprimary_email Your primary email address.\n"
66 "\tother_email A list (separated by ';') of other email addresses\n"
67 "\t at which you receive email.\n"
69 " Notmuch will use the various email addresses configured here when\n"
70 " formatting replies. It will avoid including your own addresses in the\n"
71 " recipient list of replies, and will set the From address based on the\n"
72 " address to which the original email was addressed.\n";
74 static const char maildir_config_comment[] =
75 " Maildir compatibility configuration\n"
77 " The following option is supported here:\n"
79 "\tsynchronize_flags Valid values are true and false.\n"
81 "\tIf true, then the following maildir flags (in message filenames)\n"
82 "\twill be synchronized with the corresponding notmuch tags:\n"
90 "\t\tS unread (added when 'S' flag is not present)\n"
92 "\tThe \"notmuch new\" command will notice flag changes in filenames\n"
93 "\tand update tags, while the \"notmuch tag\" and \"notmuch restore\"\n"
94 "\tcommands will notice tag changes and update flags in filenames\n";
96 static const char search_config_comment[] =
97 " Search configuration\n"
99 " The following option is supported here:\n"
102 "\t\tA ;-separated list of tags that will be excluded from\n"
103 "\t\tsearch results by default. Using an excluded tag in a\n"
104 "\t\tquery will override that exclusion.\n";
106 static const char crypto_config_comment[] =
107 " Cryptography related configuration\n"
109 " The following old option is now ignored:\n"
112 "\t\tThis option was used by older builds of notmuch to choose\n"
113 "\t\tthe version of gpg to use.\n"
114 "\t\tSetting $PATH is a better approach.\n";
116 struct _notmuch_config {
122 char *crypto_gpg_path;
124 char *user_primary_email;
125 const char **user_other_email;
126 size_t user_other_email_length;
127 const char **new_tags;
128 size_t new_tags_length;
129 const char **new_ignore;
130 size_t new_ignore_length;
131 bool maildir_synchronize_flags;
132 const char **search_exclude_tags;
133 size_t search_exclude_tags_length;
137 notmuch_config_destructor (notmuch_config_t *config)
139 if (config->key_file)
140 g_key_file_free (config->key_file);
146 get_name_from_passwd_file (void *ctx)
150 struct passwd passwd, *ignored;
154 pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX);
155 if (pw_buf_size == -1) pw_buf_size = 64;
156 pw_buf = talloc_size (ctx, pw_buf_size);
158 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
159 pw_buf_size, &ignored)) == ERANGE) {
160 pw_buf_size = pw_buf_size * 2;
161 pw_buf = talloc_zero_size (ctx, pw_buf_size);
165 char *comma = strchr (passwd.pw_gecos, ',');
167 name = talloc_strndup (ctx, passwd.pw_gecos,
168 comma - passwd.pw_gecos);
170 name = talloc_strdup (ctx, passwd.pw_gecos);
172 name = talloc_strdup (ctx, "");
175 talloc_free (pw_buf);
181 get_username_from_passwd_file (void *ctx)
185 struct passwd passwd, *ignored;
189 pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX);
190 if (pw_buf_size == -1) pw_buf_size = 64;
191 pw_buf = talloc_zero_size (ctx, pw_buf_size);
193 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
194 pw_buf_size, &ignored)) == ERANGE) {
195 pw_buf_size = pw_buf_size * 2;
196 pw_buf = talloc_zero_size (ctx, pw_buf_size);
200 name = talloc_strdup (ctx, passwd.pw_name);
202 name = talloc_strdup (ctx, "");
204 talloc_free (pw_buf);
210 get_config_from_file (notmuch_config_t *config, bool create_new)
212 #define BUF_SIZE 4096
213 char *config_str = NULL;
215 int config_bufsize = BUF_SIZE;
217 GError *error = NULL;
220 FILE *fp = fopen (config->filename, "r");
222 if (errno == ENOENT) {
223 /* If create_new is true, then the caller is prepared for a
224 * default configuration file in the case of FILE NOT FOUND.
227 config->is_new = true;
230 fprintf (stderr, "Configuration file %s not found.\n"
231 "Try running 'notmuch setup' to create a configuration.\n",
235 fprintf (stderr, "Error opening config file '%s': %s\n",
236 config->filename, strerror (errno));
241 config_str = talloc_zero_array (config, char, config_bufsize);
242 if (config_str == NULL) {
243 fprintf (stderr, "Error reading '%s': Out of memory\n", config->filename);
247 while ((len = fread (config_str + config_len, 1,
248 config_bufsize - config_len, fp)) > 0) {
250 if (config_len == config_bufsize) {
251 config_bufsize += BUF_SIZE;
252 config_str = talloc_realloc (config, config_str, char, config_bufsize);
253 if (config_str == NULL) {
254 fprintf (stderr, "Error reading '%s': Failed to reallocate memory\n",
262 fprintf (stderr, "Error reading '%s': I/O error\n", config->filename);
266 if (g_key_file_load_from_data (config->key_file, config_str, config_len,
267 G_KEY_FILE_KEEP_COMMENTS, &error)) {
272 fprintf (stderr, "Error parsing config file '%s': %s\n",
273 config->filename, error->message);
275 g_error_free (error);
282 talloc_free (config_str);
287 /* Open the named notmuch configuration file. If the filename is NULL,
288 * the value of the environment variable $NOTMUCH_CONFIG will be used.
289 * If $NOTMUCH_CONFIG is unset, the default configuration file
290 * ($HOME/.notmuch-config) will be used.
292 * If any error occurs, (out of memory, or a permission-denied error,
293 * etc.), this function will print a message to stderr and return
296 * FILE NOT FOUND: When the specified configuration file (whether from
297 * 'filename' or the $NOTMUCH_CONFIG environment variable) does not
298 * exist, the behavior of this function depends on the 'is_new_ret'
301 * If is_new_ret is NULL, then a "file not found" message will be
302 * printed to stderr and NULL will be returned.
304 * If is_new_ret is non-NULL then a default configuration will be
305 * returned and *is_new_ret will be set to 1 on return so that
306 * the caller can recognize this case.
308 * These default configuration settings are determined as
311 * database_path: $MAILDIR, otherwise $HOME/mail
313 * user_name: $NAME variable if set, otherwise
314 * read from /etc/passwd
316 * user_primary_mail: $EMAIL variable if set, otherwise
317 * constructed from the username and
318 * hostname of the current machine.
320 * user_other_email: Not set.
322 * The default configuration also contains comments to guide the
323 * user in editing the file directly.
326 notmuch_config_open (void *ctx,
327 const char *filename,
328 notmuch_config_mode_t config_mode)
330 GError *error = NULL;
332 char *notmuch_config_env = NULL;
333 int file_had_database_group;
334 int file_had_new_group;
335 int file_had_user_group;
336 int file_had_maildir_group;
337 int file_had_search_group;
338 int file_had_crypto_group;
340 notmuch_config_t *config = talloc_zero (ctx, notmuch_config_t);
342 if (config == NULL) {
343 fprintf (stderr, "Out of memory.\n");
347 talloc_set_destructor (config, notmuch_config_destructor);
349 /* non-zero defaults */
350 config->maildir_synchronize_flags = true;
353 config->filename = talloc_strdup (config, filename);
354 } else if ((notmuch_config_env = getenv ("NOTMUCH_CONFIG"))) {
355 config->filename = talloc_strdup (config, notmuch_config_env);
357 config->filename = talloc_asprintf (config, "%s/.notmuch-config",
361 config->key_file = g_key_file_new ();
363 if (config_mode & NOTMUCH_CONFIG_OPEN) {
364 bool create_new = (config_mode & NOTMUCH_CONFIG_CREATE) != 0;
366 if (! get_config_from_file (config, create_new)) {
367 talloc_free (config);
372 /* Whenever we know of configuration sections that don't appear in
373 * the configuration file, we add some comments to help the user
374 * understand what can be done.
376 * It would be convenient to just add those comments now, but
377 * apparently g_key_file will clear any comments when keys are
378 * added later that create the groups. So we have to check for the
379 * groups now, but add the comments only after setting all of our
382 file_had_database_group = g_key_file_has_group (config->key_file,
384 file_had_new_group = g_key_file_has_group (config->key_file, "new");
385 file_had_user_group = g_key_file_has_group (config->key_file, "user");
386 file_had_maildir_group = g_key_file_has_group (config->key_file, "maildir");
387 file_had_search_group = g_key_file_has_group (config->key_file, "search");
388 file_had_crypto_group = g_key_file_has_group (config->key_file, "crypto");
390 if (notmuch_config_get_database_path (config) == NULL) {
391 char *path = getenv ("MAILDIR");
393 path = talloc_strdup (config, path);
395 path = talloc_asprintf (config, "%s/mail",
397 notmuch_config_set_database_path (config, path);
401 if (notmuch_config_get_user_name (config) == NULL) {
402 char *name = getenv ("NAME");
404 name = talloc_strdup (config, name);
406 name = get_name_from_passwd_file (config);
407 notmuch_config_set_user_name (config, name);
411 if (notmuch_config_get_user_primary_email (config) == NULL) {
412 char *email = getenv ("EMAIL");
414 notmuch_config_set_user_primary_email (config, email);
417 struct hostent *hostent;
418 const char *domainname;
420 char *username = get_username_from_passwd_file (config);
422 gethostname (hostname, 256);
423 hostname[255] = '\0';
425 hostent = gethostbyname (hostname);
426 if (hostent && (domainname = strchr (hostent->h_name, '.')))
429 domainname = "(none)";
431 email = talloc_asprintf (config, "%s@%s.%s",
432 username, hostname, domainname);
434 notmuch_config_set_user_primary_email (config, email);
436 talloc_free (username);
441 if (notmuch_config_get_new_tags (config, &tmp) == NULL) {
442 const char *tags[] = { "unread", "inbox" };
443 notmuch_config_set_new_tags (config, tags, 2);
446 if (notmuch_config_get_new_ignore (config, &tmp) == NULL) {
447 notmuch_config_set_new_ignore (config, NULL, 0);
450 if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) {
451 if (config->is_new) {
452 const char *tags[] = { "deleted", "spam" };
453 notmuch_config_set_search_exclude_tags (config, tags, 2);
455 notmuch_config_set_search_exclude_tags (config, NULL, 0);
460 config->maildir_synchronize_flags =
461 g_key_file_get_boolean (config->key_file,
462 "maildir", "synchronize_flags", &error);
464 notmuch_config_set_maildir_synchronize_flags (config, true);
465 g_error_free (error);
468 /* Whenever we know of configuration sections that don't appear in
469 * the configuration file, we add some comments to help the user
470 * understand what can be done. */
472 g_key_file_set_comment (config->key_file, NULL, NULL,
473 toplevel_config_comment, NULL);
475 if (! file_had_database_group)
476 g_key_file_set_comment (config->key_file, "database", NULL,
477 database_config_comment, NULL);
479 if (! file_had_new_group)
480 g_key_file_set_comment (config->key_file, "new", NULL,
481 new_config_comment, NULL);
483 if (! file_had_user_group)
484 g_key_file_set_comment (config->key_file, "user", NULL,
485 user_config_comment, NULL);
487 if (! file_had_maildir_group)
488 g_key_file_set_comment (config->key_file, "maildir", NULL,
489 maildir_config_comment, NULL);
491 if (! file_had_search_group)
492 g_key_file_set_comment (config->key_file, "search", NULL,
493 search_config_comment, NULL);
495 if (! file_had_crypto_group)
496 g_key_file_set_comment (config->key_file, "crypto", NULL,
497 crypto_config_comment, NULL);
502 /* Close the given notmuch_config_t object, freeing all resources.
504 * Note: Any changes made to the configuration are *not* saved by this
505 * function. To save changes, call notmuch_config_save before
506 * notmuch_config_close.
509 notmuch_config_close (notmuch_config_t *config)
511 talloc_free (config);
514 /* Save any changes made to the notmuch configuration.
516 * Any comments originally in the file will be preserved.
518 * Returns 0 if successful, and 1 in case of any error, (after
519 * printing a description of the error to stderr).
522 notmuch_config_save (notmuch_config_t *config)
525 char *data, *filename;
526 GError *error = NULL;
528 data = g_key_file_to_data (config->key_file, &length, NULL);
530 fprintf (stderr, "Out of memory.\n");
534 /* Try not to overwrite symlinks. */
535 filename = canonicalize_file_name (config->filename);
537 if (errno == ENOENT) {
538 filename = strdup (config->filename);
540 fprintf (stderr, "Out of memory.\n");
545 fprintf (stderr, "Error canonicalizing %s: %s\n", config->filename,
552 if (! g_file_set_contents (filename, data, length, &error)) {
553 if (strcmp (filename, config->filename) != 0) {
554 fprintf (stderr, "Error saving configuration to %s (-> %s): %s\n",
555 config->filename, filename, error->message);
557 fprintf (stderr, "Error saving configuration to %s: %s\n",
558 filename, error->message);
560 g_error_free (error);
572 notmuch_config_is_new (notmuch_config_t *config)
574 return config->is_new;
578 _config_get (notmuch_config_t *config, char **field,
579 const char *group, const char *key)
581 /* read from config file and cache value, if not cached already */
582 if (*field == NULL) {
584 value = g_key_file_get_string (config->key_file, group, key, NULL);
586 *field = talloc_strdup (config, value);
594 _config_set (notmuch_config_t *config, char **field,
595 const char *group, const char *key, const char *value)
597 g_key_file_set_string (config->key_file, group, key, value);
599 /* drop the cached value */
600 talloc_free (*field);
605 _config_get_list (notmuch_config_t *config,
606 const char *section, const char *key,
607 const char ***outlist, size_t *list_length, size_t *ret_length)
611 /* read from config file and cache value, if not cached already */
612 if (*outlist == NULL) {
614 char **inlist = g_key_file_get_string_list (config->key_file,
615 section, key, list_length, NULL);
619 *outlist = talloc_size (config, sizeof (char *) * (*list_length + 1));
621 for (i = 0; i < *list_length; i++)
622 (*outlist)[i] = talloc_strdup (*outlist, inlist[i]);
624 (*outlist)[i] = NULL;
631 *ret_length = *list_length;
637 _config_set_list (notmuch_config_t *config,
638 const char *group, const char *key,
640 size_t length, const char ***config_var )
642 g_key_file_set_string_list (config->key_file, group, key, list, length);
644 /* drop the cached value */
645 talloc_free (*config_var);
650 notmuch_config_get_database_path (notmuch_config_t *config)
652 char *db_path = (char *) _config_get (config, &config->database_path, "database", "path");
654 if (db_path && *db_path != '/') {
655 /* If the path in the configuration file begins with any
656 * character other than /, presume that it is relative to
657 * $HOME and update as appropriate.
659 char *abs_path = talloc_asprintf (config, "%s/%s", getenv ("HOME"), db_path);
660 talloc_free (db_path);
661 db_path = config->database_path = abs_path;
668 notmuch_config_set_database_path (notmuch_config_t *config,
669 const char *database_path)
671 _config_set (config, &config->database_path, "database", "path", database_path);
675 notmuch_config_get_user_name (notmuch_config_t *config)
677 return _config_get (config, &config->user_name, "user", "name");
681 notmuch_config_set_user_name (notmuch_config_t *config,
682 const char *user_name)
684 _config_set (config, &config->user_name, "user", "name", user_name);
688 notmuch_config_get_user_primary_email (notmuch_config_t *config)
690 return _config_get (config, &config->user_primary_email, "user", "primary_email");
694 notmuch_config_set_user_primary_email (notmuch_config_t *config,
695 const char *primary_email)
697 _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email);
701 notmuch_config_get_user_other_email (notmuch_config_t *config, size_t *length)
703 return _config_get_list (config, "user", "other_email",
704 &(config->user_other_email),
705 &(config->user_other_email_length), length);
709 notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
711 return _config_get_list (config, "new", "tags",
713 &(config->new_tags_length), length);
717 notmuch_config_get_new_ignore (notmuch_config_t *config, size_t *length)
719 return _config_get_list (config, "new", "ignore",
720 &(config->new_ignore),
721 &(config->new_ignore_length), length);
725 notmuch_config_set_user_other_email (notmuch_config_t *config,
729 _config_set_list (config, "user", "other_email", list, length,
730 &(config->user_other_email));
734 notmuch_config_set_new_tags (notmuch_config_t *config,
738 _config_set_list (config, "new", "tags", list, length,
739 &(config->new_tags));
743 notmuch_config_set_new_ignore (notmuch_config_t *config,
747 _config_set_list (config, "new", "ignore", list, length,
748 &(config->new_ignore));
752 notmuch_config_get_search_exclude_tags (notmuch_config_t *config, size_t *length)
754 return _config_get_list (config, "search", "exclude_tags",
755 &(config->search_exclude_tags),
756 &(config->search_exclude_tags_length), length);
760 notmuch_config_set_search_exclude_tags (notmuch_config_t *config,
764 _config_set_list (config, "search", "exclude_tags", list, length,
765 &(config->search_exclude_tags));
769 /* Given a configuration item of the form <group>.<key> return the
770 * component group and key. If any error occurs, print a message on
771 * stderr and return 1. Otherwise, return 0.
773 * Note: This function modifies the original 'item' string.
776 _item_split (char *item, char **group, char **key)
782 period = strchr (item, '.');
783 if (period == NULL || *(period + 1) == '\0') {
785 "Invalid configuration name: %s\n"
786 "(Should be of the form <section>.<item>)\n", item);
796 /* These are more properly called Xapian fields, but the user facing
797 * docs call them prefixes, so make the error message match */
799 validate_field_name (const char *str)
803 if (! g_utf8_validate (str, -1, NULL)) {
804 fprintf (stderr, "Invalid utf8: %s\n", str);
808 key = g_utf8_strrchr (str, -1, '.');
810 INTERNAL_ERROR ("Impossible code path on input: %s\n", str);
816 fprintf (stderr, "Empty prefix name: %s\n", str);
820 if (! unicode_word_utf8 (key)) {
821 fprintf (stderr, "Non-word character in prefix name: %s\n", key);
825 if (key[0] >= 'a' && key[0] <= 'z') {
826 fprintf (stderr, "Prefix names starting with lower case letters are reserved: %s\n", key);
833 #define BUILT_WITH_PREFIX "built_with."
835 typedef struct config_key {
839 bool (*validate)(const char *);
842 static struct config_key
843 config_key_table[] = {
844 { "index.decrypt", true, false, NULL },
845 { "index.header.", true, true, validate_field_name },
846 { "query.", true, true, NULL },
849 static config_key_info_t *
850 _config_key_info (const char *item)
852 for (size_t i = 0; i < ARRAY_SIZE (config_key_table); i++) {
853 if (config_key_table[i].prefix &&
854 strncmp (item, config_key_table[i].name,
855 strlen (config_key_table[i].name)) == 0)
856 return config_key_table + i;
857 if (strcmp (item, config_key_table[i].name) == 0)
858 return config_key_table + i;
864 _stored_in_db (const char *item)
866 config_key_info_t *info;
868 info = _config_key_info (item);
870 return (info && info->in_db);
874 _print_db_config (notmuch_config_t *config, const char *name)
876 notmuch_database_t *notmuch;
879 if (notmuch_database_open (notmuch_config_get_database_path (config),
880 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
883 /* XXX Handle UUID mismatch? */
885 if (print_status_database ("notmuch config", notmuch,
886 notmuch_database_get_config (notmuch, name, &val)))
895 notmuch_config_command_get (notmuch_config_t *config, char *item)
897 if (strcmp (item, "database.path") == 0) {
898 printf ("%s\n", notmuch_config_get_database_path (config));
899 } else if (strcmp (item, "user.name") == 0) {
900 printf ("%s\n", notmuch_config_get_user_name (config));
901 } else if (strcmp (item, "user.primary_email") == 0) {
902 printf ("%s\n", notmuch_config_get_user_primary_email (config));
903 } else if (strcmp (item, "user.other_email") == 0) {
904 const char **other_email;
907 other_email = notmuch_config_get_user_other_email (config, &length);
908 for (i = 0; i < length; i++)
909 printf ("%s\n", other_email[i]);
910 } else if (strcmp (item, "new.tags") == 0) {
914 tags = notmuch_config_get_new_tags (config, &length);
915 for (i = 0; i < length; i++)
916 printf ("%s\n", tags[i]);
917 } else if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
919 notmuch_built_with (item + strlen (BUILT_WITH_PREFIX)) ? "true" : "false");
920 } else if (_stored_in_db (item)) {
921 return _print_db_config (config, item);
927 if (_item_split (item, &group, &key))
930 value = g_key_file_get_string_list (config->key_file,
934 fprintf (stderr, "Unknown configuration item: %s.%s\n",
939 for (i = 0; i < length; i++)
940 printf ("%s\n", value[i]);
949 _set_db_config (notmuch_config_t *config, const char *key, int argc, char **argv)
951 notmuch_database_t *notmuch;
952 const char *val = "";
955 /* XXX handle lists? */
956 fprintf (stderr, "notmuch config set: at most one value expected for %s\n", key);
964 if (notmuch_database_open (notmuch_config_get_database_path (config),
965 NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
968 /* XXX Handle UUID mismatch? */
970 if (print_status_database ("notmuch config", notmuch,
971 notmuch_database_set_config (notmuch, key, val)))
974 if (print_status_database ("notmuch config", notmuch,
975 notmuch_database_close (notmuch)))
982 notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[])
985 config_key_info_t *key_info;
987 if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
988 fprintf (stderr, "Error: read only option: %s\n", item);
992 key_info = _config_key_info (item);
993 if (key_info && key_info->validate && (! key_info->validate (item)))
996 if (key_info && key_info->in_db) {
997 return _set_db_config (config, item, argc, argv);
1000 if (_item_split (item, &group, &key))
1003 /* With only the name of an item, we clear it from the
1004 * configuration file.
1006 * With a single value, we set it as a string.
1008 * With multiple values, we set them as a string list.
1012 g_key_file_remove_key (config->key_file, group, key, NULL);
1015 g_key_file_set_string (config->key_file, group, key, argv[0]);
1018 g_key_file_set_string_list (config->key_file, group, key,
1019 (const gchar **) argv, argc);
1023 return notmuch_config_save (config);
1028 _notmuch_config_list_built_with ()
1030 printf ("%scompact=%s\n",
1032 notmuch_built_with ("compact") ? "true" : "false");
1033 printf ("%sfield_processor=%s\n",
1035 notmuch_built_with ("field_processor") ? "true" : "false");
1036 printf ("%sretry_lock=%s\n",
1038 notmuch_built_with ("retry_lock") ? "true" : "false");
1042 _list_db_config (notmuch_config_t *config)
1044 notmuch_database_t *notmuch;
1045 notmuch_config_list_t *list;
1047 if (notmuch_database_open (notmuch_config_get_database_path (config),
1048 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
1049 return EXIT_FAILURE;
1051 /* XXX Handle UUID mismatch? */
1054 if (print_status_database ("notmuch config", notmuch,
1055 notmuch_database_get_config_list (notmuch, "", &list)))
1056 return EXIT_FAILURE;
1058 for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
1059 printf ("%s=%s\n", notmuch_config_list_key (list), notmuch_config_list_value (list));
1061 notmuch_config_list_destroy (list);
1063 return EXIT_SUCCESS;
1067 notmuch_config_command_list (notmuch_config_t *config)
1070 size_t g, groups_length;
1072 groups = g_key_file_get_groups (config->key_file, &groups_length);
1076 for (g = 0; g < groups_length; g++) {
1078 size_t k, keys_length;
1080 keys = g_key_file_get_keys (config->key_file,
1081 groups[g], &keys_length, NULL);
1085 for (k = 0; k < keys_length; k++) {
1088 value = g_key_file_get_string (config->key_file,
1089 groups[g], keys[k], NULL);
1090 if (value != NULL) {
1091 printf ("%s.%s=%s\n", groups[g], keys[k], value);
1099 g_strfreev (groups);
1101 _notmuch_config_list_built_with ();
1102 return _list_db_config (config);
1106 notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])
1111 opt_index = notmuch_minimal_options ("config", argc, argv);
1113 return EXIT_FAILURE;
1115 if (notmuch_requested_db_uuid)
1116 fprintf (stderr, "Warning: ignoring --uuid=%s\n",
1117 notmuch_requested_db_uuid);
1119 /* skip at least subcommand argument */
1124 fprintf (stderr, "Error: notmuch config requires at least one argument.\n");
1125 return EXIT_FAILURE;
1128 if (strcmp (argv[0], "get") == 0) {
1130 fprintf (stderr, "Error: notmuch config get requires exactly "
1132 return EXIT_FAILURE;
1134 ret = notmuch_config_command_get (config, argv[1]);
1135 } else if (strcmp (argv[0], "set") == 0) {
1137 fprintf (stderr, "Error: notmuch config set requires at least "
1139 return EXIT_FAILURE;
1141 ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2);
1142 } else if (strcmp (argv[0], "list") == 0) {
1143 ret = notmuch_config_command_list (config);
1145 fprintf (stderr, "Unrecognized argument for notmuch config: %s\n",
1147 return EXIT_FAILURE;
1150 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
1155 notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config)
1157 return config->maildir_synchronize_flags;
1161 notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config,
1162 bool synchronize_flags)
1164 g_key_file_set_boolean (config->key_file,
1165 "maildir", "synchronize_flags", synchronize_flags);
1166 config->maildir_synchronize_flags = synchronize_flags;