configuration file handling polished and fixed;
This commit is contained in:
parent
2d900b0839
commit
3f0f915d99
@ -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__ */
|
|
||||||
41
include/ilib/configuration.h
Normal file
41
include/ilib/configuration.h
Normal 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__ */
|
||||||
@ -20,7 +20,7 @@
|
|||||||
#ifndef __LOCAL_H__
|
#ifndef __LOCAL_H__
|
||||||
#define __LOCAL_H__
|
#define __LOCAL_H__
|
||||||
|
|
||||||
#include <ilib/config.h>
|
#include <ilib/configuration.h>
|
||||||
#include <ilib/subscribers.h>
|
#include <ilib/subscribers.h>
|
||||||
#include <ilib/pending.h>
|
#include <ilib/pending.h>
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <ilib/config.h>
|
#include <ilib/configuration.h>
|
||||||
|
|
||||||
typedef struct mail_message {
|
typedef struct mail_message {
|
||||||
char *raw_data; /* Full raw RFC 822 byte payload */
|
char *raw_data; /* Full raw RFC 822 byte payload */
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#ifndef __MAIL_PROCESSOR_H__
|
#ifndef __MAIL_PROCESSOR_H__
|
||||||
#define __MAIL_PROCESSOR_H__
|
#define __MAIL_PROCESSOR_H__
|
||||||
|
|
||||||
#include <ilib/config.h>
|
#include <ilib/configuration.h>
|
||||||
#include <ilib/subscribers.h>
|
#include <ilib/subscribers.h>
|
||||||
#include <ilib/pending.h>
|
#include <ilib/pending.h>
|
||||||
#include <ilib/mail_engine.h>
|
#include <ilib/mail_engine.h>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
bin_PROGRAMS = subrelayd sbrlctrl
|
bin_PROGRAMS = subrelayd sbrlctrl
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
$(top_srcdir)/include/ilib/config.h \
|
$(top_srcdir)/include/ilib/configuration.h \
|
||||||
$(top_srcdir)/include/ilib/local.h \
|
$(top_srcdir)/include/ilib/local.h \
|
||||||
$(top_srcdir)/include/ilib/mail_engine.h \
|
$(top_srcdir)/include/ilib/mail_engine.h \
|
||||||
$(top_srcdir)/include/ilib/mail_processor.h \
|
$(top_srcdir)/include/ilib/mail_processor.h \
|
||||||
@ -16,7 +16,7 @@ subrelayd_SOURCES = \
|
|||||||
splay.c \
|
splay.c \
|
||||||
subscribers.c \
|
subscribers.c \
|
||||||
pending.c \
|
pending.c \
|
||||||
config.c \
|
configuration.c \
|
||||||
template.c \
|
template.c \
|
||||||
mail_engine.c \
|
mail_engine.c \
|
||||||
mail_processor.c \
|
mail_processor.c \
|
||||||
|
|||||||
@ -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 <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#include <ilib/config.h>
|
#include <ilib/configuration.h>
|
||||||
|
|
||||||
|
#define LINE_MAXLEN 1024
|
||||||
|
|
||||||
static char *trim(char *str)
|
static char *trim(char *str)
|
||||||
{
|
{
|
||||||
@ -33,19 +54,32 @@ static char *strip_quotes(char *val)
|
|||||||
return 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)
|
static void set_string_param(char **target, const char *val)
|
||||||
{
|
{
|
||||||
if (*target) free(*target);
|
if (*target) free(*target);
|
||||||
*target = strdup(val);
|
*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;
|
if (!cfg || !filepath) return -EINVAL;
|
||||||
|
|
||||||
memset(cfg, 0, sizeof(subrelay_config_t));
|
memset(cfg, 0, sizeof(subrelay_config_t));
|
||||||
|
|
||||||
/* Apply sensible defaults */
|
/* default values */
|
||||||
cfg->imap_port = 993;
|
cfg->imap_port = 993;
|
||||||
cfg->smtp_port = 587;
|
cfg->smtp_port = 587;
|
||||||
cfg->socket_path = strdup("/var/run/subrelayd.sock");
|
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");
|
FILE *fp = fopen(filepath, "r");
|
||||||
if (!fp) return -errno;
|
if (!fp) return -errno;
|
||||||
|
|
||||||
char line[1024];
|
char line[LINE_MAXLEN];
|
||||||
int line_num = 0;
|
int line_num = 0;
|
||||||
|
|
||||||
while (fgets(line, sizeof(line), fp)) {
|
while (fgets(line, sizeof(line), fp)) {
|
||||||
line_num++;
|
line_num++;
|
||||||
|
|
||||||
/* Rule C004.1: Everything after '#' is ignored */
|
/* requirement C004.1: everything after '#' is ignored -- comment */
|
||||||
char *comment = strchr(line, '#');
|
char *comment = strchr(line, '#');
|
||||||
if (comment) *comment = '\0';
|
if (comment) *comment = '\0';
|
||||||
|
|
||||||
char *trimmed = trim(line);
|
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, ':');
|
char *colon = strchr(trimmed, ':');
|
||||||
if (!colon) {
|
if (!colon) {
|
||||||
fprintf(stderr, "config: syntax error at line %d: missing ':'\n", line_num);
|
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) {
|
} else if (strcasecmp(key, "IMAP_HOST") == 0) {
|
||||||
set_string_param(&cfg->imap_host, value);
|
set_string_param(&cfg->imap_host, value);
|
||||||
} else if (strcasecmp(key, "IMAP_PORT") == 0) {
|
} 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) {
|
} else if (strcasecmp(key, "SMTP_HOST") == 0) {
|
||||||
set_string_param(&cfg->smtp_host, value);
|
set_string_param(&cfg->smtp_host, value);
|
||||||
} else if (strcasecmp(key, "SMTP_PORT") == 0) {
|
} 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) {
|
} else if (strcasecmp(key, "ACCOUNT_PASS") == 0) {
|
||||||
set_string_param(&cfg->account_pass, value);
|
set_string_param(&cfg->account_pass, value);
|
||||||
} else if (strcasecmp(key, "MAILLIST_NAME") == 0) {
|
} else if (strcasecmp(key, "MAILLIST_NAME") == 0) {
|
||||||
@ -112,14 +152,15 @@ int config_load(subrelay_config_t *cfg, const char *filepath)
|
|||||||
/* Validate essential parameters */
|
/* Validate essential parameters */
|
||||||
if (!cfg->maillist_addr || !cfg->imap_host || !cfg->smtp_host || !cfg->account_pass) {
|
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");
|
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 -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_free(subrelay_config_t *cfg)
|
void configuration_free(subrelay_config_t *cfg)
|
||||||
{
|
{
|
||||||
if (!cfg) return;
|
if (!cfg) return;
|
||||||
|
|
||||||
@ -135,4 +176,5 @@ void config_free(subrelay_config_t *cfg)
|
|||||||
if (cfg->subscribers_file)free(cfg->subscribers_file);
|
if (cfg->subscribers_file)free(cfg->subscribers_file);
|
||||||
|
|
||||||
memset(cfg, 0, sizeof(subrelay_config_t));
|
memset(cfg, 0, sizeof(subrelay_config_t));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
@ -30,7 +30,7 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
|
||||||
#include <ilib/config.h>
|
#include <ilib/configuration.h>
|
||||||
#include <ilib/subscribers.h>
|
#include <ilib/subscribers.h>
|
||||||
#include <ilib/pending.h>
|
#include <ilib/pending.h>
|
||||||
#include <ilib/mail_engine.h>
|
#include <ilib/mail_engine.h>
|
||||||
@ -127,7 +127,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
/* 1. Load Configuration */
|
/* 1. Load Configuration */
|
||||||
subrelay_config_t cfg;
|
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);
|
fprintf(stderr, "error: failed to load config file '%s'\n", config_path);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@ -136,7 +136,7 @@ int main(int argc, char **argv)
|
|||||||
subscriber_pool_t subscribers;
|
subscriber_pool_t subscribers;
|
||||||
if (subscriber_pool_init(&subscribers, cfg.subscribers_file) != 0) {
|
if (subscriber_pool_init(&subscribers, cfg.subscribers_file) != 0) {
|
||||||
fprintf(stderr, "error: failed to initialize subscriber pool\n");
|
fprintf(stderr, "error: failed to initialize subscriber pool\n");
|
||||||
config_free(&cfg);
|
configuration_free(&cfg);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
subscriber_load_file(&subscribers);
|
subscriber_load_file(&subscribers);
|
||||||
@ -148,7 +148,7 @@ int main(int argc, char **argv)
|
|||||||
if (pending_pool_init(&pending, pending_path, 86400) != 0) {
|
if (pending_pool_init(&pending, pending_path, 86400) != 0) {
|
||||||
fprintf(stderr, "error: failed to initialize pending pool\n");
|
fprintf(stderr, "error: failed to initialize pending pool\n");
|
||||||
subscriber_pool_destroy(&subscribers);
|
subscriber_pool_destroy(&subscribers);
|
||||||
config_free(&cfg);
|
configuration_free(&cfg);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
pending_load_file(&pending);
|
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);
|
fprintf(stderr, "error: failed to bind IPC socket '%s'\n", cfg.socket_path);
|
||||||
pending_pool_destroy(&pending);
|
pending_pool_destroy(&pending);
|
||||||
subscriber_pool_destroy(&subscribers);
|
subscriber_pool_destroy(&subscribers);
|
||||||
config_free(&cfg);
|
configuration_free(&cfg);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ int main(int argc, char **argv)
|
|||||||
local_ctrl_destroy(&ipc);
|
local_ctrl_destroy(&ipc);
|
||||||
pending_pool_destroy(&pending);
|
pending_pool_destroy(&pending);
|
||||||
subscriber_pool_destroy(&subscribers);
|
subscriber_pool_destroy(&subscribers);
|
||||||
config_free(&cfg);
|
configuration_free(&cfg);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ int main(int argc, char **argv)
|
|||||||
local_ctrl_destroy(&ipc);
|
local_ctrl_destroy(&ipc);
|
||||||
pending_pool_destroy(&pending);
|
pending_pool_destroy(&pending);
|
||||||
subscriber_pool_destroy(&subscribers);
|
subscriber_pool_destroy(&subscribers);
|
||||||
config_free(&cfg);
|
configuration_free(&cfg);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ int main(int argc, char **argv)
|
|||||||
local_ctrl_destroy(&ipc);
|
local_ctrl_destroy(&ipc);
|
||||||
pending_pool_destroy(&pending);
|
pending_pool_destroy(&pending);
|
||||||
subscriber_pool_destroy(&subscribers);
|
subscriber_pool_destroy(&subscribers);
|
||||||
config_free(&cfg);
|
configuration_free(&cfg);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user