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 {
123 char *user_primary_email;
124 const char **user_other_email;
125 size_t user_other_email_length;
126 const char **new_tags;
127 size_t new_tags_length;
128 const char **new_ignore;
129 size_t new_ignore_length;
130 bool maildir_synchronize_flags;
131 const char **search_exclude_tags;
132 size_t search_exclude_tags_length;
136 notmuch_config_destructor (notmuch_config_t *config)
138 if (config->key_file)
139 g_key_file_free (config->key_file);
145 get_name_from_passwd_file (void *ctx)
149 struct passwd passwd, *ignored;
153 pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX);
154 if (pw_buf_size == -1) pw_buf_size = 64;
155 pw_buf = talloc_size (ctx, pw_buf_size);
157 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
158 pw_buf_size, &ignored)) == ERANGE) {
159 pw_buf_size = pw_buf_size * 2;
160 pw_buf = talloc_zero_size (ctx, pw_buf_size);
164 char *comma = strchr (passwd.pw_gecos, ',');
166 name = talloc_strndup (ctx, passwd.pw_gecos,
167 comma - passwd.pw_gecos);
169 name = talloc_strdup (ctx, passwd.pw_gecos);
171 name = talloc_strdup (ctx, "");
174 talloc_free (pw_buf);
180 get_username_from_passwd_file (void *ctx)
184 struct passwd passwd, *ignored;
188 pw_buf_size = sysconf (_SC_GETPW_R_SIZE_MAX);
189 if (pw_buf_size == -1) pw_buf_size = 64;
190 pw_buf = talloc_zero_size (ctx, pw_buf_size);
192 while ((e = getpwuid_r (getuid (), &passwd, pw_buf,
193 pw_buf_size, &ignored)) == ERANGE) {
194 pw_buf_size = pw_buf_size * 2;
195 pw_buf = talloc_zero_size (ctx, pw_buf_size);
199 name = talloc_strdup (ctx, passwd.pw_name);
201 name = talloc_strdup (ctx, "");
203 talloc_free (pw_buf);
209 get_config_from_file (notmuch_config_t *config, bool create_new)
211 #define BUF_SIZE 4096
212 char *config_str = NULL;
214 int config_bufsize = BUF_SIZE;
216 GError *error = NULL;
219 FILE *fp = fopen (config->filename, "r");
221 if (errno == ENOENT) {
222 /* If create_new is true, then the caller is prepared for a
223 * default configuration file in the case of FILE NOT FOUND.
226 config->is_new = true;
229 fprintf (stderr, "Configuration file %s not found.\n"
230 "Try running 'notmuch setup' to create a configuration.\n",
234 fprintf (stderr, "Error opening config file '%s': %s\n",
235 config->filename, strerror (errno));
240 config_str = talloc_zero_array (config, char, config_bufsize);
241 if (config_str == NULL) {
242 fprintf (stderr, "Error reading '%s': Out of memory\n", config->filename);
246 while ((len = fread (config_str + config_len, 1,
247 config_bufsize - config_len, fp)) > 0) {
249 if (config_len == config_bufsize) {
250 config_bufsize += BUF_SIZE;
251 config_str = talloc_realloc (config, config_str, char, config_bufsize);
252 if (config_str == NULL) {
253 fprintf (stderr, "Error reading '%s': Failed to reallocate memory\n",
261 fprintf (stderr, "Error reading '%s': I/O error\n", config->filename);
265 if (g_key_file_load_from_data (config->key_file, config_str, config_len,
266 G_KEY_FILE_KEEP_COMMENTS, &error)) {
271 fprintf (stderr, "Error parsing config file '%s': %s\n",
272 config->filename, error->message);
274 g_error_free (error);
281 talloc_free (config_str);
286 /* Open the named notmuch configuration file. If the filename is NULL,
287 * the value of the environment variable $NOTMUCH_CONFIG will be used.
288 * If $NOTMUCH_CONFIG is unset, the default configuration file
289 * ($HOME/.notmuch-config) will be used.
291 * If any error occurs, (out of memory, or a permission-denied error,
292 * etc.), this function will print a message to stderr and return
295 * FILE NOT FOUND: When the specified configuration file (whether from
296 * 'filename' or the $NOTMUCH_CONFIG environment variable) does not
297 * exist, the behavior of this function depends on the 'is_new_ret'
300 * If is_new_ret is NULL, then a "file not found" message will be
301 * printed to stderr and NULL will be returned.
303 * If is_new_ret is non-NULL then a default configuration will be
304 * returned and *is_new_ret will be set to 1 on return so that
305 * the caller can recognize this case.
307 * These default configuration settings are determined as
310 * database_path: $MAILDIR, otherwise $HOME/mail
312 * user_name: $NAME variable if set, otherwise
313 * read from /etc/passwd
315 * user_primary_mail: $EMAIL variable if set, otherwise
316 * constructed from the username and
317 * hostname of the current machine.
319 * user_other_email: Not set.
321 * The default configuration also contains comments to guide the
322 * user in editing the file directly.
325 notmuch_config_open (void *ctx,
326 const char *filename,
327 notmuch_command_mode_t config_mode)
329 GError *error = NULL;
331 char *notmuch_config_env = NULL;
332 int file_had_database_group;
333 int file_had_new_group;
334 int file_had_user_group;
335 int file_had_maildir_group;
336 int file_had_search_group;
337 int file_had_crypto_group;
339 notmuch_config_t *config = talloc_zero (ctx, notmuch_config_t);
341 if (config == NULL) {
342 fprintf (stderr, "Out of memory.\n");
346 talloc_set_destructor (config, notmuch_config_destructor);
348 /* non-zero defaults */
349 config->maildir_synchronize_flags = true;
352 config->filename = talloc_strdup (config, filename);
353 } else if ((notmuch_config_env = getenv ("NOTMUCH_CONFIG"))) {
354 config->filename = talloc_strdup (config, notmuch_config_env);
356 config->filename = talloc_asprintf (config, "%s/.notmuch-config",
360 config->key_file = g_key_file_new ();
362 if (config_mode & NOTMUCH_COMMAND_CONFIG_OPEN) {
363 bool create_new = (config_mode & NOTMUCH_COMMAND_CONFIG_CREATE) != 0;
365 if (! get_config_from_file (config, create_new)) {
366 talloc_free (config);
371 /* Whenever we know of configuration sections that don't appear in
372 * the configuration file, we add some comments to help the user
373 * understand what can be done.
375 * It would be convenient to just add those comments now, but
376 * apparently g_key_file will clear any comments when keys are
377 * added later that create the groups. So we have to check for the
378 * groups now, but add the comments only after setting all of our
381 file_had_database_group = g_key_file_has_group (config->key_file,
383 file_had_new_group = g_key_file_has_group (config->key_file, "new");
384 file_had_user_group = g_key_file_has_group (config->key_file, "user");
385 file_had_maildir_group = g_key_file_has_group (config->key_file, "maildir");
386 file_had_search_group = g_key_file_has_group (config->key_file, "search");
387 file_had_crypto_group = g_key_file_has_group (config->key_file, "crypto");
389 if (notmuch_config_get_database_path (config) == NULL) {
390 char *path = getenv ("MAILDIR");
392 path = talloc_strdup (config, path);
394 path = talloc_asprintf (config, "%s/mail",
396 notmuch_config_set_database_path (config, path);
400 if (notmuch_config_get_user_name (config) == NULL) {
401 char *name = getenv ("NAME");
403 name = talloc_strdup (config, name);
405 name = get_name_from_passwd_file (config);
406 notmuch_config_set_user_name (config, name);
410 if (notmuch_config_get_user_primary_email (config) == NULL) {
411 char *email = getenv ("EMAIL");
413 notmuch_config_set_user_primary_email (config, email);
416 struct hostent *hostent;
417 const char *domainname;
419 char *username = get_username_from_passwd_file (config);
421 gethostname (hostname, 256);
422 hostname[255] = '\0';
424 hostent = gethostbyname (hostname);
425 if (hostent && (domainname = strchr (hostent->h_name, '.')))
428 domainname = "(none)";
430 email = talloc_asprintf (config, "%s@%s.%s",
431 username, hostname, domainname);
433 notmuch_config_set_user_primary_email (config, email);
435 talloc_free (username);
440 if (notmuch_config_get_new_tags (config, &tmp) == NULL) {
441 const char *tags[] = { "unread", "inbox" };
442 notmuch_config_set_new_tags (config, tags, 2);
445 if (notmuch_config_get_new_ignore (config, &tmp) == NULL) {
446 notmuch_config_set_new_ignore (config, NULL, 0);
449 if (notmuch_config_get_search_exclude_tags (config, &tmp) == NULL) {
450 if (config->is_new) {
451 const char *tags[] = { "deleted", "spam" };
452 notmuch_config_set_search_exclude_tags (config, tags, 2);
454 notmuch_config_set_search_exclude_tags (config, NULL, 0);
459 config->maildir_synchronize_flags =
460 g_key_file_get_boolean (config->key_file,
461 "maildir", "synchronize_flags", &error);
463 notmuch_config_set_maildir_synchronize_flags (config, true);
464 g_error_free (error);
467 /* Whenever we know of configuration sections that don't appear in
468 * the configuration file, we add some comments to help the user
469 * understand what can be done. */
471 g_key_file_set_comment (config->key_file, NULL, NULL,
472 toplevel_config_comment, NULL);
474 if (! file_had_database_group)
475 g_key_file_set_comment (config->key_file, "database", NULL,
476 database_config_comment, NULL);
478 if (! file_had_new_group)
479 g_key_file_set_comment (config->key_file, "new", NULL,
480 new_config_comment, NULL);
482 if (! file_had_user_group)
483 g_key_file_set_comment (config->key_file, "user", NULL,
484 user_config_comment, NULL);
486 if (! file_had_maildir_group)
487 g_key_file_set_comment (config->key_file, "maildir", NULL,
488 maildir_config_comment, NULL);
490 if (! file_had_search_group)
491 g_key_file_set_comment (config->key_file, "search", NULL,
492 search_config_comment, NULL);
494 if (! file_had_crypto_group)
495 g_key_file_set_comment (config->key_file, "crypto", NULL,
496 crypto_config_comment, NULL);
501 /* Close the given notmuch_config_t object, freeing all resources.
503 * Note: Any changes made to the configuration are *not* saved by this
504 * function. To save changes, call notmuch_config_save before
505 * notmuch_config_close.
508 notmuch_config_close (notmuch_config_t *config)
510 talloc_free (config);
514 _notmuch_config_get_path (notmuch_config_t *config)
516 return config->filename;
518 /* Save any changes made to the notmuch configuration.
520 * Any comments originally in the file will be preserved.
522 * Returns 0 if successful, and 1 in case of any error, (after
523 * printing a description of the error to stderr).
526 notmuch_config_save (notmuch_config_t *config)
529 char *data, *filename;
530 GError *error = NULL;
532 data = g_key_file_to_data (config->key_file, &length, NULL);
534 fprintf (stderr, "Out of memory.\n");
538 /* Try not to overwrite symlinks. */
539 filename = canonicalize_file_name (config->filename);
541 if (errno == ENOENT) {
542 filename = strdup (config->filename);
544 fprintf (stderr, "Out of memory.\n");
549 fprintf (stderr, "Error canonicalizing %s: %s\n", config->filename,
556 if (! g_file_set_contents (filename, data, length, &error)) {
557 if (strcmp (filename, config->filename) != 0) {
558 fprintf (stderr, "Error saving configuration to %s (-> %s): %s\n",
559 config->filename, filename, error->message);
561 fprintf (stderr, "Error saving configuration to %s: %s\n",
562 filename, error->message);
564 g_error_free (error);
576 notmuch_config_is_new (notmuch_config_t *config)
578 return config->is_new;
582 _config_get (notmuch_config_t *config, char **field,
583 const char *group, const char *key)
585 /* read from config file and cache value, if not cached already */
586 if (*field == NULL) {
588 value = g_key_file_get_string (config->key_file, group, key, NULL);
590 *field = talloc_strdup (config, value);
598 _config_set (notmuch_config_t *config, char **field,
599 const char *group, const char *key, const char *value)
601 g_key_file_set_string (config->key_file, group, key, value);
603 /* drop the cached value */
604 talloc_free (*field);
609 _config_get_list (notmuch_config_t *config,
610 const char *section, const char *key,
611 const char ***outlist, size_t *list_length, size_t *ret_length)
615 /* read from config file and cache value, if not cached already */
616 if (*outlist == NULL) {
618 char **inlist = g_key_file_get_string_list (config->key_file,
619 section, key, list_length, NULL);
623 *outlist = talloc_size (config, sizeof (char *) * (*list_length + 1));
625 for (i = 0; i < *list_length; i++)
626 (*outlist)[i] = talloc_strdup (*outlist, inlist[i]);
628 (*outlist)[i] = NULL;
635 *ret_length = *list_length;
641 _config_set_list (notmuch_config_t *config,
642 const char *group, const char *key,
644 size_t length, const char ***config_var )
646 g_key_file_set_string_list (config->key_file, group, key, list, length);
648 /* drop the cached value */
649 talloc_free (*config_var);
654 notmuch_config_get_database_path (notmuch_config_t *config)
656 char *db_path = (char *) _config_get (config, &config->database_path, "database", "path");
658 if (db_path && *db_path != '/') {
659 /* If the path in the configuration file begins with any
660 * character other than /, presume that it is relative to
661 * $HOME and update as appropriate.
663 char *abs_path = talloc_asprintf (config, "%s/%s", getenv ("HOME"), db_path);
664 talloc_free (db_path);
665 db_path = config->database_path = abs_path;
672 notmuch_config_set_database_path (notmuch_config_t *config,
673 const char *database_path)
675 _config_set (config, &config->database_path, "database", "path", database_path);
679 notmuch_config_get_user_name (notmuch_config_t *config)
681 return _config_get (config, &config->user_name, "user", "name");
685 notmuch_config_set_user_name (notmuch_config_t *config,
686 const char *user_name)
688 _config_set (config, &config->user_name, "user", "name", user_name);
692 notmuch_config_get_user_primary_email (notmuch_config_t *config)
694 return _config_get (config, &config->user_primary_email, "user", "primary_email");
698 notmuch_config_set_user_primary_email (notmuch_config_t *config,
699 const char *primary_email)
701 _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email);
705 notmuch_config_get_user_other_email (notmuch_config_t *config, size_t *length)
707 return _config_get_list (config, "user", "other_email",
708 &(config->user_other_email),
709 &(config->user_other_email_length), length);
713 notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
715 return _config_get_list (config, "new", "tags",
717 &(config->new_tags_length), length);
721 notmuch_config_get_new_ignore (notmuch_config_t *config, size_t *length)
723 return _config_get_list (config, "new", "ignore",
724 &(config->new_ignore),
725 &(config->new_ignore_length), length);
729 notmuch_config_set_user_other_email (notmuch_config_t *config,
733 _config_set_list (config, "user", "other_email", list, length,
734 &(config->user_other_email));
738 notmuch_config_set_new_tags (notmuch_config_t *config,
742 _config_set_list (config, "new", "tags", list, length,
743 &(config->new_tags));
747 notmuch_config_set_new_ignore (notmuch_config_t *config,
751 _config_set_list (config, "new", "ignore", list, length,
752 &(config->new_ignore));
756 notmuch_config_get_search_exclude_tags (notmuch_config_t *config, size_t *length)
758 return _config_get_list (config, "search", "exclude_tags",
759 &(config->search_exclude_tags),
760 &(config->search_exclude_tags_length), length);
764 notmuch_config_set_search_exclude_tags (notmuch_config_t *config,
768 _config_set_list (config, "search", "exclude_tags", list, length,
769 &(config->search_exclude_tags));
773 /* Given a configuration item of the form <group>.<key> return the
774 * component group and key. If any error occurs, print a message on
775 * stderr and return 1. Otherwise, return 0.
777 * Note: This function modifies the original 'item' string.
780 _item_split (char *item, char **group, char **key)
786 period = strchr (item, '.');
787 if (period == NULL || *(period + 1) == '\0') {
789 "Invalid configuration name: %s\n"
790 "(Should be of the form <section>.<item>)\n", item);
800 /* These are more properly called Xapian fields, but the user facing
801 * docs call them prefixes, so make the error message match */
803 validate_field_name (const char *str)
807 if (! g_utf8_validate (str, -1, NULL)) {
808 fprintf (stderr, "Invalid utf8: %s\n", str);
812 key = g_utf8_strrchr (str, -1, '.');
814 INTERNAL_ERROR ("Impossible code path on input: %s\n", str);
820 fprintf (stderr, "Empty prefix name: %s\n", str);
824 if (! unicode_word_utf8 (key)) {
825 fprintf (stderr, "Non-word character in prefix name: %s\n", key);
829 if (key[0] >= 'a' && key[0] <= 'z') {
830 fprintf (stderr, "Prefix names starting with lower case letters are reserved: %s\n", key);
837 #define BUILT_WITH_PREFIX "built_with."
839 typedef struct config_key {
843 bool (*validate)(const char *);
846 static struct config_key
847 config_key_table[] = {
848 { "index.decrypt", true, false, NULL },
849 { "index.header.", true, true, validate_field_name },
850 { "query.", true, true, NULL },
853 static config_key_info_t *
854 _config_key_info (const char *item)
856 for (size_t i = 0; i < ARRAY_SIZE (config_key_table); i++) {
857 if (config_key_table[i].prefix &&
858 strncmp (item, config_key_table[i].name,
859 strlen (config_key_table[i].name)) == 0)
860 return config_key_table + i;
861 if (strcmp (item, config_key_table[i].name) == 0)
862 return config_key_table + i;
868 _stored_in_db (const char *item)
870 config_key_info_t *info;
872 info = _config_key_info (item);
874 return (info && info->in_db);
878 _print_db_config (notmuch_config_t *config, const char *name)
880 notmuch_database_t *notmuch;
883 if (notmuch_database_open (notmuch_config_get_database_path (config),
884 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
887 /* XXX Handle UUID mismatch? */
889 if (print_status_database ("notmuch config", notmuch,
890 notmuch_database_get_config (notmuch, name, &val)))
899 notmuch_config_command_get (notmuch_config_t *config, char *item)
901 if (strcmp (item, "database.path") == 0) {
902 printf ("%s\n", notmuch_config_get_database_path (config));
903 } else if (strcmp (item, "user.name") == 0) {
904 printf ("%s\n", notmuch_config_get_user_name (config));
905 } else if (strcmp (item, "user.primary_email") == 0) {
906 printf ("%s\n", notmuch_config_get_user_primary_email (config));
907 } else if (strcmp (item, "user.other_email") == 0) {
908 const char **other_email;
911 other_email = notmuch_config_get_user_other_email (config, &length);
912 for (i = 0; i < length; i++)
913 printf ("%s\n", other_email[i]);
914 } else if (strcmp (item, "new.tags") == 0) {
918 tags = notmuch_config_get_new_tags (config, &length);
919 for (i = 0; i < length; i++)
920 printf ("%s\n", tags[i]);
921 } else if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
923 notmuch_built_with (item + strlen (BUILT_WITH_PREFIX)) ? "true" : "false");
924 } else if (_stored_in_db (item)) {
925 return _print_db_config (config, item);
931 if (_item_split (item, &group, &key))
934 value = g_key_file_get_string_list (config->key_file,
938 fprintf (stderr, "Unknown configuration item: %s.%s\n",
943 for (i = 0; i < length; i++)
944 printf ("%s\n", value[i]);
953 _set_db_config (notmuch_config_t *config, const char *key, int argc, char **argv)
955 notmuch_database_t *notmuch;
956 const char *val = "";
959 /* XXX handle lists? */
960 fprintf (stderr, "notmuch config set: at most one value expected for %s\n", key);
968 if (notmuch_database_open (notmuch_config_get_database_path (config),
969 NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
972 /* XXX Handle UUID mismatch? */
974 if (print_status_database ("notmuch config", notmuch,
975 notmuch_database_set_config (notmuch, key, val)))
978 if (print_status_database ("notmuch config", notmuch,
979 notmuch_database_close (notmuch)))
986 notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[])
989 config_key_info_t *key_info;
991 if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
992 fprintf (stderr, "Error: read only option: %s\n", item);
996 key_info = _config_key_info (item);
997 if (key_info && key_info->validate && (! key_info->validate (item)))
1000 if (key_info && key_info->in_db) {
1001 return _set_db_config (config, item, argc, argv);
1004 if (_item_split (item, &group, &key))
1007 /* With only the name of an item, we clear it from the
1008 * configuration file.
1010 * With a single value, we set it as a string.
1012 * With multiple values, we set them as a string list.
1016 g_key_file_remove_key (config->key_file, group, key, NULL);
1019 g_key_file_set_string (config->key_file, group, key, argv[0]);
1022 g_key_file_set_string_list (config->key_file, group, key,
1023 (const gchar **) argv, argc);
1027 return notmuch_config_save (config);
1032 _notmuch_config_list_built_with ()
1034 printf ("%scompact=%s\n",
1036 notmuch_built_with ("compact") ? "true" : "false");
1037 printf ("%sfield_processor=%s\n",
1039 notmuch_built_with ("field_processor") ? "true" : "false");
1040 printf ("%sretry_lock=%s\n",
1042 notmuch_built_with ("retry_lock") ? "true" : "false");
1046 _list_db_config (notmuch_config_t *config)
1048 notmuch_database_t *notmuch;
1049 notmuch_config_list_t *list;
1051 if (notmuch_database_open (notmuch_config_get_database_path (config),
1052 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
1053 return EXIT_FAILURE;
1055 /* XXX Handle UUID mismatch? */
1058 if (print_status_database ("notmuch config", notmuch,
1059 notmuch_database_get_config_list (notmuch, "", &list)))
1060 return EXIT_FAILURE;
1062 for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
1063 printf ("%s=%s\n", notmuch_config_list_key (list), notmuch_config_list_value (list));
1065 notmuch_config_list_destroy (list);
1067 return EXIT_SUCCESS;
1071 notmuch_config_command_list (notmuch_config_t *config)
1074 size_t g, groups_length;
1076 groups = g_key_file_get_groups (config->key_file, &groups_length);
1080 for (g = 0; g < groups_length; g++) {
1082 size_t k, keys_length;
1084 keys = g_key_file_get_keys (config->key_file,
1085 groups[g], &keys_length, NULL);
1089 for (k = 0; k < keys_length; k++) {
1092 value = g_key_file_get_string (config->key_file,
1093 groups[g], keys[k], NULL);
1094 if (value != NULL) {
1095 printf ("%s.%s=%s\n", groups[g], keys[k], value);
1103 g_strfreev (groups);
1105 _notmuch_config_list_built_with ();
1106 return _list_db_config (config);
1110 notmuch_config_command (notmuch_config_t *config, unused(notmuch_database_t *notmuch),
1111 int argc, char *argv[])
1116 opt_index = notmuch_minimal_options ("config", argc, argv);
1118 return EXIT_FAILURE;
1120 if (notmuch_requested_db_uuid)
1121 fprintf (stderr, "Warning: ignoring --uuid=%s\n",
1122 notmuch_requested_db_uuid);
1124 /* skip at least subcommand argument */
1129 fprintf (stderr, "Error: notmuch config requires at least one argument.\n");
1130 return EXIT_FAILURE;
1133 if (strcmp (argv[0], "get") == 0) {
1135 fprintf (stderr, "Error: notmuch config get requires exactly "
1137 return EXIT_FAILURE;
1139 ret = notmuch_config_command_get (config, argv[1]);
1140 } else if (strcmp (argv[0], "set") == 0) {
1142 fprintf (stderr, "Error: notmuch config set requires at least "
1144 return EXIT_FAILURE;
1146 ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2);
1147 } else if (strcmp (argv[0], "list") == 0) {
1148 ret = notmuch_config_command_list (config);
1150 fprintf (stderr, "Unrecognized argument for notmuch config: %s\n",
1152 return EXIT_FAILURE;
1155 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
1160 notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config)
1162 return config->maildir_synchronize_flags;
1166 notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config,
1167 bool synchronize_flags)
1169 g_key_file_set_boolean (config->key_file,
1170 "maildir", "synchronize_flags", synchronize_flags);
1171 config->maildir_synchronize_flags = synchronize_flags;