bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#include "lib.h"
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen#include "str.h"
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#include "istream.h"
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen#include "strescape.h"
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#include "settings.h"
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#include <stdio.h>
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#include <fcntl.h>
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen#ifdef HAVE_GLOB_H
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen# include <glob.h>
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen#endif
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen#ifndef GLOB_BRACE
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen# define GLOB_BRACE 0
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen#endif
4e0204dbac352e271c79cfa6c74a71145a058de5Timo Sirainen
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen#define SECTION_ERRORMSG "%s (section changed in %s at line %d)"
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainenstruct input_stack {
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen struct input_stack *prev;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen struct istream *input;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen const char *path;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen unsigned int linenum;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen};
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainensettings_section_callback_t *null_settings_section_callback = NULL;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic const char *get_bool(const char *value, bool *result)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen{
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen if (strcasecmp(value, "yes") == 0)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen *result = TRUE;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen else if (strcasecmp(value, "no") == 0)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen *result = FALSE;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen else
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen return t_strconcat("Invalid boolean: ", value, NULL);
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen return NULL;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen}
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainenstatic const char *get_uint(const char *value, unsigned int *result)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen{
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen int num;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
bd8b391d7d2112e989963980663ef8cb0469b35cTimo Sirainen if (sscanf(value, "%i", &num) != 1 || num < 0)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen return t_strconcat("Invalid number: ", value, NULL);
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen *result = num;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen return NULL;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen}
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainenconst char *
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenparse_setting_from_defs(pool_t pool, const struct setting_def *defs, void *base,
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen const char *key, const char *value)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen{
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen const struct setting_def *def;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen for (def = defs; def->name != NULL; def++) {
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen if (strcmp(def->name, key) == 0) {
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen void *ptr = STRUCT_MEMBER_P(base, def->offset);
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen switch (def->type) {
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen case SET_STR:
8892c76722fdbceec5bd519d32e65985ecd35c31Timo Sirainen *((char **)ptr) = p_strdup(pool, value);
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen return NULL;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen case SET_INT:
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen /* use %i so we can handle eg. 0600
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen as octal value with umasks */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen return get_uint(value, (unsigned int *) ptr);
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen case SET_BOOL:
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen return get_bool(value, (bool *) ptr);
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen return t_strconcat("Unknown setting: ", key, NULL);
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen}
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainenstatic const char *
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainenfix_relative_path(const char *path, struct input_stack *input)
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen{
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen const char *p;
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen if (*path == '/')
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen return path;
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen p = strrchr(input->path, '/');
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen if (p == NULL)
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen return path;
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen return t_strconcat(t_strdup_until(input->path, p+1), path, NULL);
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen}
90441432cfe7a5bf7ee07c91c57f4027946ee4f1Timo Sirainen
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainenstatic int settings_add_include(const char *path, struct input_stack **inputp,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen bool ignore_errors, const char **error_r)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen{
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct input_stack *tmp, *new_input;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen int fd;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen for (tmp = *inputp; tmp != NULL; tmp = tmp->prev) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if (strcmp(tmp->path, path) == 0)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen break;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen }
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if (tmp != NULL) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = t_strdup_printf("Recursive include file: %s", path);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return -1;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen }
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if ((fd = open(path, O_RDONLY)) == -1) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if (ignore_errors)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return 0;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = t_strdup_printf("Couldn't open include file %s: %m",
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen path);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return -1;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen }
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen new_input = t_new(struct input_stack, 1);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen new_input->prev = *inputp;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen new_input->path = t_strdup(path);
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen new_input->input = i_stream_create_fd_autoclose(&fd, (size_t)-1);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen i_stream_set_return_partial_line(new_input->input, TRUE);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *inputp = new_input;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return 0;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen}
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainenstatic int
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainensettings_include(const char *pattern, struct input_stack **inputp,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen bool ignore_errors, const char **error_r)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen{
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen#ifdef HAVE_GLOB
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen glob_t globbers;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen unsigned int i;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen switch (glob(pattern, GLOB_BRACE, NULL, &globbers)) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen case 0:
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen break;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen case GLOB_NOSPACE:
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = "glob() failed: Not enough memory";
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return -1;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen case GLOB_ABORTED:
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = "glob() failed: Read error";
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return -1;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen case GLOB_NOMATCH:
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if (ignore_errors)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return 0;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = "No matches";
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return -1;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen default:
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen *error_r = "glob() failed: Unknown error";
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return -1;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen }
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi /* iterate through the different files matching the globbing */
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen for (i = 0; i < globbers.gl_pathc; i++) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if (settings_add_include(globbers.gl_pathv[i], inputp,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen ignore_errors, error_r) < 0)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return -1;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen }
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen globfree(&globbers);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return 0;
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen#else
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen return settings_add_include(pattern, inputp, ignore_errors, error_r);
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen#endif
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen}
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainenbool settings_read_i(const char *path, const char *section,
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen settings_callback_t *callback,
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen settings_section_callback_t *sect_callback, void *context,
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen const char **error_r)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen{
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen /* pretty horrible code, but v2.0 will have this rewritten anyway.. */
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen struct input_stack root, *input;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen const char *errormsg, *next_section, *name, *last_section_path = NULL;
73583cff4f0ca9ee87204256ca1994adf17cb94cTimo Sirainen char *line, *key, *p, quote;
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen string_t *full_line;
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen size_t len;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen int fd, last_section_line = 0, skip, sections, root_section;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen fd = open(path, O_RDONLY);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (fd < 0) {
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen *error_r = t_strdup_printf(
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen "Can't open configuration file %s: %m", path);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen return FALSE;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (section == NULL) {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen skip = 0;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen next_section = NULL;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen } else {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen skip = 1;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen next_section = t_strcut(section, '/');
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&root);
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen root.path = path;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen input = &root;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen full_line = t_str_new(512);
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen sections = 0; root_section = 0; errormsg = NULL;
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen input->input = i_stream_create_fd_autoclose(&fd, (size_t)-1);
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen i_stream_set_return_partial_line(input->input, TRUE);
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainenprevfile:
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen while ((line = i_stream_read_next_line(input->input)) != NULL) {
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen input->linenum++;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen /* @UNSAFE: line is modified */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen /* skip whitespace */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen while (IS_WHITE(*line))
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen line++;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen /* ignore comments or empty lines */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen if (*line == '#' || *line == '\0')
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen continue;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen /* strip away comments. pretty kludgy way really.. */
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen for (p = line; *p != '\0'; p++) {
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen if (*p == '\'' || *p == '"') {
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen quote = *p;
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen for (p++; *p != quote && *p != '\0'; p++) {
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen if (*p == '\\' && p[1] != '\0')
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen p++;
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen }
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen if (*p == '\0')
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen break;
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen } else if (*p == '#') {
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen if (!IS_WHITE(p[-1])) {
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen i_warning("Configuration file %s line %u: "
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen "Ambiguous '#' character in line, treating it as comment. "
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen "Add a space before it to remove this warning.",
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen input->path, input->linenum);
25e480bc781fdbcbee1d8b88ccdef163c0c63b0fTimo Sirainen }
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen *p = '\0';
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen break;
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen }
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen }
6cc8fac7fd9b47e179629a61acef0e8758763803Timo Sirainen
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen /* remove whitespace from end of line */
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen len = strlen(line);
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen while (IS_WHITE(line[len-1]))
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen len--;
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen line[len] = '\0';
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen if (len > 0 && line[len-1] == '\\') {
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen /* continues in next line */
c8154bfaf4f08f4b1b038ae4483ea703789c9be6Timo Sirainen len--;
c8154bfaf4f08f4b1b038ae4483ea703789c9be6Timo Sirainen while (IS_WHITE(line[len-1]))
c8154bfaf4f08f4b1b038ae4483ea703789c9be6Timo Sirainen len--;
c8154bfaf4f08f4b1b038ae4483ea703789c9be6Timo Sirainen str_append_n(full_line, line, len);
c8154bfaf4f08f4b1b038ae4483ea703789c9be6Timo Sirainen str_append_c(full_line, ' ');
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen continue;
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen }
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen if (str_len(full_line) > 0) {
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen str_append(full_line, line);
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen line = str_c_modifiable(full_line);
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen }
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen /* a) key = value
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen b) section_type [section_name] {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen c) } */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen key = line;
337e0bdea4c5b1a9e3ac3e915b31a6413f46220cTimo Sirainen while (!IS_WHITE(*line) && *line != '\0' && *line != '=')
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen line++;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen if (IS_WHITE(*line)) {
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen *line++ = '\0';
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen while (IS_WHITE(*line)) line++;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen if (strcmp(key, "!include_try") == 0 ||
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen strcmp(key, "!include") == 0) {
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen if (settings_include(fix_relative_path(line, input),
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen &input,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen strcmp(key, "!include_try") == 0,
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen &errormsg) == 0)
a78d5bd9772681a232de56b3dd6acefee66cc71bTimo Sirainen goto prevfile;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen } else if (*line == '=') {
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen /* a) */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen *line++ = '\0';
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen while (IS_WHITE(*line)) line++;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen len = strlen(line);
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen if (len > 0 &&
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen ((*line == '"' && line[len-1] == '"') ||
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen (*line == '\'' && line[len-1] == '\''))) {
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen line[len-1] = '\0';
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen line = str_unescape(line+1);
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen }
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen errormsg = skip > 0 ? NULL :
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen callback(key, line, context);
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen } else if (strcmp(key, "}") != 0 || *line != '\0') {
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen /* b) + errors */
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen line[-1] = '\0';
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen if (*line == '{')
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen name = "";
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen else {
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen name = line;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen while (!IS_WHITE(*line) && *line != '\0')
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen line++;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen if (*line != '\0') {
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen *line++ = '\0';
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen while (IS_WHITE(*line))
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen line++;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen if (*line != '{')
84e83fa1f6ec489b473a94ab7698c5b4a9987541Timo Sirainen errormsg = "Expecting '='";
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen else {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen sections++;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (next_section != NULL &&
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen strcmp(next_section, name) == 0) {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen section += strlen(next_section);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (*section == '\0') {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen skip = 0;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen next_section = NULL;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen root_section = sections;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen } else {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen i_assert(*section == '/');
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen section++;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen next_section =
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen t_strcut(section, '/');
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (skip > 0)
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen skip++;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen else {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen skip = sect_callback == NULL ? 1 :
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen !sect_callback(key, name,
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen context,
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen &errormsg);
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen if (errormsg != NULL &&
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen last_section_line != 0) {
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen errormsg = t_strdup_printf(
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen SECTION_ERRORMSG,
7761b23ef311d4a27ed78ad864287b290d4066f2Timo Sirainen errormsg,
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen last_section_path,
7761b23ef311d4a27ed78ad864287b290d4066f2Timo Sirainen last_section_line);
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen last_section_path = input->path;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen last_section_line = input->linenum;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen } else {
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen /* c) */
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen if (sections == 0)
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen errormsg = "Unexpected '}'";
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen else {
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen if (skip > 0)
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen skip--;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen else {
48325adac125d7ff275ec69b05b7a92be9637630Timo Sirainen i_assert(sect_callback != NULL);
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen sect_callback(NULL, NULL, context,
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen &errormsg);
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen if (root_section == sections &&
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen errormsg == NULL) {
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen /* we found the section,
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen now quit */
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen break;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen }
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen }
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen last_section_path = input->path;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen last_section_line = input->linenum;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen sections--;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen if (errormsg != NULL) {
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen *error_r = t_strdup_printf(
803197abb1cc0e81abb668c026c22394bfef820dTimo Sirainen "Error in configuration file %s line %d: %s",
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen input->path, input->linenum, errormsg);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen break;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
12bbab623d9965d019e6e80d4f41255cd5002c9aTimo Sirainen str_truncate(full_line, 0);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen i_stream_destroy(&input->input);
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen input = input->prev;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen if (line == NULL && input != NULL)
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen goto prevfile;
885673616ab8dc038eafdf76efe4184ecffcdc88Timo Sirainen
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen return errormsg == NULL;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen}