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);
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_CONFIG_OPEN) {
363 bool create_new = (config_mode & NOTMUCH_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);
513 /* Save any changes made to the notmuch configuration.
515 * Any comments originally in the file will be preserved.
517 * Returns 0 if successful, and 1 in case of any error, (after
518 * printing a description of the error to stderr).
521 notmuch_config_save (notmuch_config_t *config)
524 char *data, *filename;
525 GError *error = NULL;
527 data = g_key_file_to_data (config->key_file, &length, NULL);
529 fprintf (stderr, "Out of memory.\n");
533 /* Try not to overwrite symlinks. */
534 filename = canonicalize_file_name (config->filename);
536 if (errno == ENOENT) {
537 filename = strdup (config->filename);
539 fprintf (stderr, "Out of memory.\n");
544 fprintf (stderr, "Error canonicalizing %s: %s\n", config->filename,
551 if (! g_file_set_contents (filename, data, length, &error)) {
552 if (strcmp (filename, config->filename) != 0) {
553 fprintf (stderr, "Error saving configuration to %s (-> %s): %s\n",
554 config->filename, filename, error->message);
556 fprintf (stderr, "Error saving configuration to %s: %s\n",
557 filename, error->message);
559 g_error_free (error);
571 notmuch_config_is_new (notmuch_config_t *config)
573 return config->is_new;
577 _config_get (notmuch_config_t *config, char **field,
578 const char *group, const char *key)
580 /* read from config file and cache value, if not cached already */
581 if (*field == NULL) {
583 value = g_key_file_get_string (config->key_file, group, key, NULL);
585 *field = talloc_strdup (config, value);
593 _config_set (notmuch_config_t *config, char **field,
594 const char *group, const char *key, const char *value)
596 g_key_file_set_string (config->key_file, group, key, value);
598 /* drop the cached value */
599 talloc_free (*field);
604 _config_get_list (notmuch_config_t *config,
605 const char *section, const char *key,
606 const char ***outlist, size_t *list_length, size_t *ret_length)
610 /* read from config file and cache value, if not cached already */
611 if (*outlist == NULL) {
613 char **inlist = g_key_file_get_string_list (config->key_file,
614 section, key, list_length, NULL);
618 *outlist = talloc_size (config, sizeof (char *) * (*list_length + 1));
620 for (i = 0; i < *list_length; i++)
621 (*outlist)[i] = talloc_strdup (*outlist, inlist[i]);
623 (*outlist)[i] = NULL;
630 *ret_length = *list_length;
636 _config_set_list (notmuch_config_t *config,
637 const char *group, const char *key,
639 size_t length, const char ***config_var )
641 g_key_file_set_string_list (config->key_file, group, key, list, length);
643 /* drop the cached value */
644 talloc_free (*config_var);
649 notmuch_config_get_database_path (notmuch_config_t *config)
651 char *db_path = (char *)_config_get (config, &config->database_path, "database", "path");
653 if (db_path && *db_path != '/') {
654 /* If the path in the configuration file begins with any
655 * character other than /, presume that it is relative to
656 * $HOME and update as appropriate.
658 char *abs_path = talloc_asprintf (config, "%s/%s", getenv ("HOME"), db_path);
659 talloc_free (db_path);
660 db_path = config->database_path = abs_path;
667 notmuch_config_set_database_path (notmuch_config_t *config,
668 const char *database_path)
670 _config_set (config, &config->database_path, "database", "path", database_path);
674 notmuch_config_get_user_name (notmuch_config_t *config)
676 return _config_get (config, &config->user_name, "user", "name");
680 notmuch_config_set_user_name (notmuch_config_t *config,
681 const char *user_name)
683 _config_set (config, &config->user_name, "user", "name", user_name);
687 notmuch_config_get_user_primary_email (notmuch_config_t *config)
689 return _config_get (config, &config->user_primary_email, "user", "primary_email");
693 notmuch_config_set_user_primary_email (notmuch_config_t *config,
694 const char *primary_email)
696 _config_set (config, &config->user_primary_email, "user", "primary_email", primary_email);
700 notmuch_config_get_user_other_email (notmuch_config_t *config, size_t *length)
702 return _config_get_list (config, "user", "other_email",
703 &(config->user_other_email),
704 &(config->user_other_email_length), length);
708 notmuch_config_get_new_tags (notmuch_config_t *config, size_t *length)
710 return _config_get_list (config, "new", "tags",
712 &(config->new_tags_length), length);
716 notmuch_config_get_new_ignore (notmuch_config_t *config, size_t *length)
718 return _config_get_list (config, "new", "ignore",
719 &(config->new_ignore),
720 &(config->new_ignore_length), length);
724 notmuch_config_set_user_other_email (notmuch_config_t *config,
728 _config_set_list (config, "user", "other_email", list, length,
729 &(config->user_other_email));
733 notmuch_config_set_new_tags (notmuch_config_t *config,
737 _config_set_list (config, "new", "tags", list, length,
738 &(config->new_tags));
742 notmuch_config_set_new_ignore (notmuch_config_t *config,
746 _config_set_list (config, "new", "ignore", list, length,
747 &(config->new_ignore));
751 notmuch_config_get_search_exclude_tags (notmuch_config_t *config, size_t *length)
753 return _config_get_list (config, "search", "exclude_tags",
754 &(config->search_exclude_tags),
755 &(config->search_exclude_tags_length), length);
759 notmuch_config_set_search_exclude_tags (notmuch_config_t *config,
763 _config_set_list (config, "search", "exclude_tags", list, length,
764 &(config->search_exclude_tags));
768 /* Given a configuration item of the form <group>.<key> return the
769 * component group and key. If any error occurs, print a message on
770 * stderr and return 1. Otherwise, return 0.
772 * Note: This function modifies the original 'item' string.
775 _item_split (char *item, char **group, char **key)
781 period = strchr (item, '.');
782 if (period == NULL || *(period+1) == '\0') {
784 "Invalid configuration name: %s\n"
785 "(Should be of the form <section>.<item>)\n", item);
795 /* These are more properly called Xapian fields, but the user facing
796 docs call them prefixes, so make the error message match */
798 validate_field_name (const char *str)
802 if (! g_utf8_validate (str, -1, NULL)) {
803 fprintf (stderr, "Invalid utf8: %s\n", str);
807 key = g_utf8_strrchr (str, -1, '.');
809 INTERNAL_ERROR ("Impossible code path on input: %s\n", str);
815 fprintf (stderr, "Empty prefix name: %s\n", str);
819 if (! unicode_word_utf8 (key)) {
820 fprintf (stderr, "Non-word character in prefix name: %s\n", key);
824 if (key[0] >= 'a' && key[0] <= 'z') {
825 fprintf (stderr, "Prefix names starting with lower case letters are reserved: %s\n", key);
832 #define BUILT_WITH_PREFIX "built_with."
834 typedef struct config_key {
838 bool (*validate)(const char *);
841 static struct config_key
842 config_key_table[] = {
843 {"index.decrypt", true, false, NULL},
844 {"index.header.", true, true, validate_field_name},
845 {"query.", true, true, NULL},
848 static config_key_info_t *
849 _config_key_info (const char *item)
851 for (size_t i = 0; i < ARRAY_SIZE (config_key_table); i++) {
852 if (config_key_table[i].prefix &&
853 strncmp (item, config_key_table[i].name,
854 strlen(config_key_table[i].name)) == 0)
855 return config_key_table+i;
856 if (strcmp (item, config_key_table[i].name) == 0)
857 return config_key_table+i;
863 _stored_in_db (const char *item)
865 config_key_info_t *info;
866 info = _config_key_info (item);
868 return (info && info->in_db);
872 _print_db_config(notmuch_config_t *config, const char *name)
874 notmuch_database_t *notmuch;
877 if (notmuch_database_open (notmuch_config_get_database_path (config),
878 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
881 /* XXX Handle UUID mismatch? */
883 if (print_status_database ("notmuch config", notmuch,
884 notmuch_database_get_config (notmuch, name, &val)))
893 notmuch_config_command_get (notmuch_config_t *config, char *item)
895 if (strcmp(item, "database.path") == 0) {
896 printf ("%s\n", notmuch_config_get_database_path (config));
897 } else if (strcmp(item, "user.name") == 0) {
898 printf ("%s\n", notmuch_config_get_user_name (config));
899 } else if (strcmp(item, "user.primary_email") == 0) {
900 printf ("%s\n", notmuch_config_get_user_primary_email (config));
901 } else if (strcmp(item, "user.other_email") == 0) {
902 const char **other_email;
905 other_email = notmuch_config_get_user_other_email (config, &length);
906 for (i = 0; i < length; i++)
907 printf ("%s\n", other_email[i]);
908 } else if (strcmp(item, "new.tags") == 0) {
912 tags = notmuch_config_get_new_tags (config, &length);
913 for (i = 0; i < length; i++)
914 printf ("%s\n", tags[i]);
915 } else if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
917 notmuch_built_with (item + strlen (BUILT_WITH_PREFIX)) ? "true" : "false");
918 } else if (_stored_in_db (item)) {
919 return _print_db_config (config, item);
925 if (_item_split (item, &group, &key))
928 value = g_key_file_get_string_list (config->key_file,
932 fprintf (stderr, "Unknown configuration item: %s.%s\n",
937 for (i = 0; i < length; i++)
938 printf ("%s\n", value[i]);
947 _set_db_config(notmuch_config_t *config, const char *key, int argc, char **argv)
949 notmuch_database_t *notmuch;
950 const char *val = "";
953 /* XXX handle lists? */
954 fprintf (stderr, "notmuch config set: at most one value expected for %s\n", key);
962 if (notmuch_database_open (notmuch_config_get_database_path (config),
963 NOTMUCH_DATABASE_MODE_READ_WRITE, ¬much))
966 /* XXX Handle UUID mismatch? */
968 if (print_status_database ("notmuch config", notmuch,
969 notmuch_database_set_config (notmuch, key, val)))
972 if (print_status_database ("notmuch config", notmuch,
973 notmuch_database_close (notmuch)))
980 notmuch_config_command_set (notmuch_config_t *config, char *item, int argc, char *argv[])
983 config_key_info_t *key_info;
985 if (STRNCMP_LITERAL (item, BUILT_WITH_PREFIX) == 0) {
986 fprintf (stderr, "Error: read only option: %s\n", item);
990 key_info = _config_key_info (item);
991 if (key_info && key_info->validate && (! key_info->validate (item)))
994 if (key_info && key_info->in_db) {
995 return _set_db_config (config, item, argc, argv);
998 if (_item_split (item, &group, &key))
1001 /* With only the name of an item, we clear it from the
1002 * configuration file.
1004 * With a single value, we set it as a string.
1006 * With multiple values, we set them as a string list.
1010 g_key_file_remove_key (config->key_file, group, key, NULL);
1013 g_key_file_set_string (config->key_file, group, key, argv[0]);
1016 g_key_file_set_string_list (config->key_file, group, key,
1017 (const gchar **) argv, argc);
1021 return notmuch_config_save (config);
1026 _notmuch_config_list_built_with ()
1028 printf("%scompact=%s\n",
1030 notmuch_built_with ("compact") ? "true" : "false");
1031 printf("%sfield_processor=%s\n",
1033 notmuch_built_with ("field_processor") ? "true" : "false");
1034 printf("%sretry_lock=%s\n",
1036 notmuch_built_with ("retry_lock") ? "true" : "false");
1040 _list_db_config (notmuch_config_t *config)
1042 notmuch_database_t *notmuch;
1043 notmuch_config_list_t *list;
1045 if (notmuch_database_open (notmuch_config_get_database_path (config),
1046 NOTMUCH_DATABASE_MODE_READ_ONLY, ¬much))
1047 return EXIT_FAILURE;
1049 /* XXX Handle UUID mismatch? */
1052 if (print_status_database ("notmuch config", notmuch,
1053 notmuch_database_get_config_list (notmuch, "", &list)))
1054 return EXIT_FAILURE;
1056 for (; notmuch_config_list_valid (list); notmuch_config_list_move_to_next (list)) {
1057 printf("%s=%s\n", notmuch_config_list_key (list), notmuch_config_list_value(list));
1059 notmuch_config_list_destroy (list);
1061 return EXIT_SUCCESS;
1065 notmuch_config_command_list (notmuch_config_t *config)
1068 size_t g, groups_length;
1070 groups = g_key_file_get_groups (config->key_file, &groups_length);
1074 for (g = 0; g < groups_length; g++) {
1076 size_t k, keys_length;
1078 keys = g_key_file_get_keys (config->key_file,
1079 groups[g], &keys_length, NULL);
1083 for (k = 0; k < keys_length; k++) {
1086 value = g_key_file_get_string (config->key_file,
1087 groups[g], keys[k], NULL);
1088 if (value != NULL) {
1089 printf ("%s.%s=%s\n", groups[g], keys[k], value);
1097 g_strfreev (groups);
1099 _notmuch_config_list_built_with ();
1100 return _list_db_config (config);
1104 notmuch_config_command (notmuch_config_t *config, int argc, char *argv[])
1109 opt_index = notmuch_minimal_options ("config", argc, argv);
1111 return EXIT_FAILURE;
1113 if (notmuch_requested_db_uuid)
1114 fprintf (stderr, "Warning: ignoring --uuid=%s\n",
1115 notmuch_requested_db_uuid);
1117 /* skip at least subcommand argument */
1122 fprintf (stderr, "Error: notmuch config requires at least one argument.\n");
1123 return EXIT_FAILURE;
1126 if (strcmp (argv[0], "get") == 0) {
1128 fprintf (stderr, "Error: notmuch config get requires exactly "
1130 return EXIT_FAILURE;
1132 ret = notmuch_config_command_get (config, argv[1]);
1133 } else if (strcmp (argv[0], "set") == 0) {
1135 fprintf (stderr, "Error: notmuch config set requires at least "
1137 return EXIT_FAILURE;
1139 ret = notmuch_config_command_set (config, argv[1], argc - 2, argv + 2);
1140 } else if (strcmp (argv[0], "list") == 0) {
1141 ret = notmuch_config_command_list (config);
1143 fprintf (stderr, "Unrecognized argument for notmuch config: %s\n",
1145 return EXIT_FAILURE;
1148 return ret ? EXIT_FAILURE : EXIT_SUCCESS;
1153 notmuch_config_get_maildir_synchronize_flags (notmuch_config_t *config)
1155 return config->maildir_synchronize_flags;
1159 notmuch_config_set_maildir_synchronize_flags (notmuch_config_t *config,
1160 bool synchronize_flags)
1162 g_key_file_set_boolean (config->key_file,
1163 "maildir", "synchronize_flags", synchronize_flags);
1164 config->maildir_synchronize_flags = synchronize_flags;