configuration file handling polished and fixed;

This commit is contained in:
Alexander Vdolainen 2026-10-13 01:56:01 +03:00
parent 2d900b0839
commit 3f0f915d99
8 changed files with 108 additions and 48 deletions

View File

@ -1,23 +0,0 @@
/* config.h - Subrelayd configuration loader */
#ifndef __CONFIG_H__
#define __CONFIG_H__
typedef struct subrelay_config {
char *maillist_addr; /* C001.1 */
char *imap_host; /* C001.2 */
int imap_port; /* C001.2 */
char *smtp_host; /* C001.3 */
int smtp_port; /* C001.3 */
char *account_pass; /* C001.4 */
char *maillist_name; /* C001.5 */
char *template_path; /* C001.6 */
char *run_user; /* C001.7 */
char *run_group; /* C001.7 */
char *socket_path; /* C001.8 */
char *subscribers_file;/* C001.9 */
} subrelay_config_t;
int config_load(subrelay_config_t *cfg, const char *filepath);
void config_free(subrelay_config_t *cfg);
#endif /* __CONFIG_H__ */

View File

@ -0,0 +1,41 @@
/*
* this is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* this is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
*
* (c) Alexander Vdolainen 2026 <alex@vapaa.xyz>
* subrelay: a minimalistic maillist server based on external IMAPs/SMTPs
*
* configuration.h: configuration file handling
*/
#ifndef __CONFIG_H__
#define __CONFIG_H__
typedef struct subrelay_config {
char *maillist_addr; /* C001.1 */
char *imap_host; /* C001.2 */
int imap_port; /* C001.2 */
char *smtp_host; /* C001.3 */
int smtp_port; /* C001.3 */
char *account_pass; /* C001.4 */
char *maillist_name; /* C001.5 */
char *template_path; /* C001.6 */
char *run_user; /* C001.7 */
char *run_group; /* C001.7 */
char *socket_path; /* C001.8 */
char *subscribers_file;/* C001.9 */
} subrelay_config_t;
int configuration_load(subrelay_config_t *cfg, const char *filepath);
void configuration_free(subrelay_config_t *cfg);
#endif /* __CONFIG_H__ */

View File

@ -20,7 +20,7 @@
#ifndef __LOCAL_H__
#define __LOCAL_H__
#include <ilib/config.h>
#include <ilib/configuration.h>
#include <ilib/subscribers.h>
#include <ilib/pending.h>

View File

@ -4,7 +4,7 @@
#include <stddef.h>
#include <ilib/config.h>
#include <ilib/configuration.h>
typedef struct mail_message {
char *raw_data; /* Full raw RFC 822 byte payload */

View File

@ -2,7 +2,7 @@
#ifndef __MAIL_PROCESSOR_H__
#define __MAIL_PROCESSOR_H__
#include <ilib/config.h>
#include <ilib/configuration.h>
#include <ilib/subscribers.h>
#include <ilib/pending.h>
#include <ilib/mail_engine.h>

View File

@ -1,7 +1,7 @@
bin_PROGRAMS = subrelayd sbrlctrl
noinst_HEADERS = \
$(top_srcdir)/include/ilib/config.h \
$(top_srcdir)/include/ilib/configuration.h \
$(top_srcdir)/include/ilib/local.h \
$(top_srcdir)/include/ilib/mail_engine.h \
$(top_srcdir)/include/ilib/mail_processor.h \
@ -16,7 +16,7 @@ subrelayd_SOURCES = \
splay.c \
subscribers.c \
pending.c \
config.c \
configuration.c \
template.c \
mail_engine.c \
mail_processor.c \

View File

@ -1,11 +1,32 @@
/* config.c - Key-value configuration parser for subrelayd */
/*
* this is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* this is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.";
*
* (c) Alexander Vdolainen 2026 <alex@vapaa.xyz>
* subrelay: a minimalistic maillist server based on external IMAPs/SMTPs
*
* configuration.c: configuration file handling
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <ilib/config.h>
#include <ilib/configuration.h>
#define LINE_MAXLEN 1024
static char *trim(char *str)
{
@ -33,19 +54,32 @@ static char *strip_quotes(char *val)
return val;
}
static int text2port(const char *value, int *port)
{
char *end;
long n = strtol(value, &end, 10);
if (value == end || errno == ERANGE || *trim(end) != '\0' ||
n < 1 || n > 65535)
return -EINVAL;
*port = (int)n;
return 0;
}
static void set_string_param(char **target, const char *val)
{
if (*target) free(*target);
*target = strdup(val);
}
int config_load(subrelay_config_t *cfg, const char *filepath)
int configuration_load(subrelay_config_t *cfg, const char *filepath)
{
if (!cfg || !filepath) return -EINVAL;
memset(cfg, 0, sizeof(subrelay_config_t));
/* Apply sensible defaults */
/* default values */
cfg->imap_port = 993;
cfg->smtp_port = 587;
cfg->socket_path = strdup("/var/run/subrelayd.sock");
@ -56,20 +90,20 @@ int config_load(subrelay_config_t *cfg, const char *filepath)
FILE *fp = fopen(filepath, "r");
if (!fp) return -errno;
char line[1024];
char line[LINE_MAXLEN];
int line_num = 0;
while (fgets(line, sizeof(line), fp)) {
line_num++;
/* Rule C004.1: Everything after '#' is ignored */
/* requirement C004.1: everything after '#' is ignored -- comment */
char *comment = strchr(line, '#');
if (comment) *comment = '\0';
char *trimmed = trim(line);
if (*trimmed == '\0') continue; /* Skip empty/comment lines */
if (*trimmed == '\0') continue; /* skip empty/comment lines */
/* Rule C004.2: <KEY>: '<VALUE>' */
/* requirement C004.2: <KEY>: '<VALUE>' */
char *colon = strchr(trimmed, ':');
if (!colon) {
fprintf(stderr, "config: syntax error at line %d: missing ':'\n", line_num);
@ -85,11 +119,17 @@ int config_load(subrelay_config_t *cfg, const char *filepath)
} else if (strcasecmp(key, "IMAP_HOST") == 0) {
set_string_param(&cfg->imap_host, value);
} else if (strcasecmp(key, "IMAP_PORT") == 0) {
cfg->imap_port = atoi(value);
if (text2port(value, &(cfg->imap_port))) {
fprintf(stderr, "config: IMAP port value is invalid at %d\n", line_num);
goto syntax_error;
}
} else if (strcasecmp(key, "SMTP_HOST") == 0) {
set_string_param(&cfg->smtp_host, value);
} else if (strcasecmp(key, "SMTP_PORT") == 0) {
cfg->smtp_port = atoi(value);
if (text2port(value, &(cfg->smtp_port))) {
fprintf(stderr, "config: SMTP port value is invalid at %d\n", line_num);
goto syntax_error;
}
} else if (strcasecmp(key, "ACCOUNT_PASS") == 0) {
set_string_param(&cfg->account_pass, value);
} else if (strcasecmp(key, "MAILLIST_NAME") == 0) {
@ -112,14 +152,15 @@ int config_load(subrelay_config_t *cfg, const char *filepath)
/* Validate essential parameters */
if (!cfg->maillist_addr || !cfg->imap_host || !cfg->smtp_host || !cfg->account_pass) {
fprintf(stderr, "config error: missing mandatory credentials (MAILLIST_ADDR, IMAP_HOST, SMTP_HOST, ACCOUNT_PASS)\n");
config_free(cfg);
syntax_error:
configuration_free(cfg);
return -EINVAL;
}
return 0;
}
void config_free(subrelay_config_t *cfg)
void configuration_free(subrelay_config_t *cfg)
{
if (!cfg) return;
@ -135,4 +176,5 @@ void config_free(subrelay_config_t *cfg)
if (cfg->subscribers_file)free(cfg->subscribers_file);
memset(cfg, 0, sizeof(subrelay_config_t));
return;
}

View File

@ -30,7 +30,7 @@
#include <pwd.h>
#include <grp.h>
#include <ilib/config.h>
#include <ilib/configuration.h>
#include <ilib/subscribers.h>
#include <ilib/pending.h>
#include <ilib/mail_engine.h>
@ -127,7 +127,7 @@ int main(int argc, char **argv)
/* 1. Load Configuration */
subrelay_config_t cfg;
if (config_load(&cfg, config_path) != 0) {
if (configuration_load(&cfg, config_path) != 0) {
fprintf(stderr, "error: failed to load config file '%s'\n", config_path);
return EXIT_FAILURE;
}
@ -136,7 +136,7 @@ int main(int argc, char **argv)
subscriber_pool_t subscribers;
if (subscriber_pool_init(&subscribers, cfg.subscribers_file) != 0) {
fprintf(stderr, "error: failed to initialize subscriber pool\n");
config_free(&cfg);
configuration_free(&cfg);
return EXIT_FAILURE;
}
subscriber_load_file(&subscribers);
@ -148,7 +148,7 @@ int main(int argc, char **argv)
if (pending_pool_init(&pending, pending_path, 86400) != 0) {
fprintf(stderr, "error: failed to initialize pending pool\n");
subscriber_pool_destroy(&subscribers);
config_free(&cfg);
configuration_free(&cfg);
return EXIT_FAILURE;
}
pending_load_file(&pending);
@ -159,7 +159,7 @@ int main(int argc, char **argv)
fprintf(stderr, "error: failed to bind IPC socket '%s'\n", cfg.socket_path);
pending_pool_destroy(&pending);
subscriber_pool_destroy(&subscribers);
config_free(&cfg);
configuration_free(&cfg);
return EXIT_FAILURE;
}
@ -169,7 +169,7 @@ int main(int argc, char **argv)
local_ctrl_destroy(&ipc);
pending_pool_destroy(&pending);
subscriber_pool_destroy(&subscribers);
config_free(&cfg);
configuration_free(&cfg);
return EXIT_FAILURE;
}
@ -179,7 +179,7 @@ int main(int argc, char **argv)
local_ctrl_destroy(&ipc);
pending_pool_destroy(&pending);
subscriber_pool_destroy(&subscribers);
config_free(&cfg);
configuration_free(&cfg);
return EXIT_FAILURE;
}
@ -231,7 +231,7 @@ int main(int argc, char **argv)
local_ctrl_destroy(&ipc);
pending_pool_destroy(&pending);
subscriber_pool_destroy(&subscribers);
config_free(&cfg);
configuration_free(&cfg);
return EXIT_SUCCESS;
}