settings.c revision 317f390961bd996932acf3d4bfbbf16c3d21e755
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#include "lib.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>
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen#define SECTION_ERRORMSG "%s (section changed at line %d)"
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
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen if (!sscanf(value, "%i", &num) || 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 *
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainenparse_setting_from_defs(pool_t pool, struct setting_def *defs, void *base,
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen const char *key, const char *value)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen{
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen 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
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen#undef settings_read
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool settings_read(const char *path, const char *section,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen settings_callback_t *callback,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen settings_section_callback_t *sect_callback, void *context)
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen{
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen struct istream *input;
73583cff4f0ca9ee87204256ca1994adf17cb94cTimo Sirainen const char *errormsg, *next_section, *name;
73583cff4f0ca9ee87204256ca1994adf17cb94cTimo Sirainen char *line, *key, *p, quote;
3f8a5d2a09e90961d1d86dea294be162ccdb64a8Timo Sirainen size_t len;
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen int fd, linenum, last_section_line = 0, skip, sections, root_section;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen fd = open(path, O_RDONLY);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen if (fd < 0) {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen i_error("Can't open configuration file %s: %m", path);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen return FALSE;
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen t_push();
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
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen linenum = 0; sections = 0; root_section = 0; errormsg = NULL;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen input = i_stream_create_file(fd, default_pool, 2048, TRUE);
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen for (;;) {
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen line = i_stream_read_next_line(input);
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen if (line == NULL) {
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen /* EOF. Also handle the last line even if it doesn't
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen contain LF. */
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen const unsigned char *data;
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen size_t size;
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen data = i_stream_get_data(input, &size);
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen if (size == 0)
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen break;
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen line = t_strdup_noconst(t_strndup(data, size));
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen i_stream_skip(input, size);
6bfd8baac71b2c4ab7191834da36e843ae0dbd14Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen 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 == '#') {
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
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
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen 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
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen errormsg = skip ? 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 {
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen last_section_line = linenum;
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,
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen errormsg, linenum);
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
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 {
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 }
317f390961bd996932acf3d4bfbbf16c3d21e755Timo Sirainen last_section_line = linenum;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen sections--;
d81433c272dc189ff50ecde109cd0040f21fa8b0Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen if (errormsg != NULL) {
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen i_error("Error in configuration file %s line %d: %s",
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen path, linenum, errormsg);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen break;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen }
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen }
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_stream_destroy(&input);
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen t_pop();
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen
0cb57ee35d4cab9c03434d7abf312c081ed554d4Timo Sirainen return errormsg == NULL;
9e49712b9cddbf47568ea4f3676e59b151489356Timo Sirainen}