diff --git a/include/ilib/config.h b/include/ilib/config.h
deleted file mode 100644
index b48a638..0000000
--- a/include/ilib/config.h
+++ /dev/null
@@ -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__ */
diff --git a/include/ilib/configuration.h b/include/ilib/configuration.h
new file mode 100644
index 0000000..fb76707
--- /dev/null
+++ b/include/ilib/configuration.h
@@ -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 .";
+ *
+ * (c) Alexander Vdolainen 2026
+ * 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__ */
diff --git a/include/ilib/local.h b/include/ilib/local.h
index d37766d..ede676c 100644
--- a/include/ilib/local.h
+++ b/include/ilib/local.h
@@ -20,7 +20,7 @@
#ifndef __LOCAL_H__
#define __LOCAL_H__
-#include
+#include
#include
#include
diff --git a/include/ilib/mail_engine.h b/include/ilib/mail_engine.h
index f41c1c5..b78baaf 100644
--- a/include/ilib/mail_engine.h
+++ b/include/ilib/mail_engine.h
@@ -4,7 +4,7 @@
#include
-#include
+#include
typedef struct mail_message {
char *raw_data; /* Full raw RFC 822 byte payload */
diff --git a/include/ilib/mail_processor.h b/include/ilib/mail_processor.h
index 41d2f6a..69f2d91 100644
--- a/include/ilib/mail_processor.h
+++ b/include/ilib/mail_processor.h
@@ -2,7 +2,7 @@
#ifndef __MAIL_PROCESSOR_H__
#define __MAIL_PROCESSOR_H__
-#include
+#include
#include
#include
#include
diff --git a/src/Makefile.am b/src/Makefile.am
index 85431c9..e355822 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -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 \
diff --git a/src/config.c b/src/configuration.c
similarity index 66%
rename from src/config.c
rename to src/configuration.c
index e26180a..e8142a9 100644
--- a/src/config.c
+++ b/src/configuration.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 .";
+ *
+ * (c) Alexander Vdolainen 2026
+ * subrelay: a minimalistic maillist server based on external IMAPs/SMTPs
+ *
+ * configuration.c: configuration file handling
+ */
+
#include
#include
#include
#include
#include
-#include
+#include
+
+#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: : '' */
+ /* requirement C004.2: : '' */
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;
}
diff --git a/src/subrelayd.c b/src/subrelayd.c
index 91c93fa..ad31881 100644
--- a/src/subrelayd.c
+++ b/src/subrelayd.c
@@ -30,7 +30,7 @@
#include
#include
-#include
+#include
#include
#include
#include
@@ -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;
}