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