control utility polishing and minor fixes, renamed;
This commit is contained in:
parent
747f30df68
commit
91d74e0bc9
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
.deps
|
.deps
|
||||||
subrelayd
|
subrelayd
|
||||||
subrelay-shell
|
subrelay-shell
|
||||||
|
sbrlctrl
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
bin_PROGRAMS = subrelayd subrelay-shell
|
bin_PROGRAMS = subrelayd sbrlctrl
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
$(top_srcdir)/include/ilib/config.h \
|
$(top_srcdir)/include/ilib/config.h \
|
||||||
$(top_srcdir)/include/ilib/ipc.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 \
|
||||||
$(top_srcdir)/include/ilib/pending.h \
|
$(top_srcdir)/include/ilib/pending.h \
|
||||||
@ -10,9 +10,7 @@ noinst_HEADERS = \
|
|||||||
$(top_srcdir)/include/ilib/subscribers.h \
|
$(top_srcdir)/include/ilib/subscribers.h \
|
||||||
$(top_srcdir)/include/ilib/template.h
|
$(top_srcdir)/include/ilib/template.h
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# daemon sources
|
||||||
# subrelayd Daemon
|
|
||||||
# ------------------------------------------------------------------------------
|
|
||||||
subrelayd_SOURCES = \
|
subrelayd_SOURCES = \
|
||||||
subrelayd.c \
|
subrelayd.c \
|
||||||
splay.c \
|
splay.c \
|
||||||
@ -22,18 +20,15 @@ subrelayd_SOURCES = \
|
|||||||
template.c \
|
template.c \
|
||||||
mail_engine.c \
|
mail_engine.c \
|
||||||
mail_processor.c \
|
mail_processor.c \
|
||||||
ipc.c
|
local.c
|
||||||
|
|
||||||
# Include internal header search path and PKG_CHECK libcurl flags
|
|
||||||
subrelayd_CPPFLAGS = -I$(top_srcdir)/include -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE $(CURL_CFLAGS)
|
subrelayd_CPPFLAGS = -I$(top_srcdir)/include -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE $(CURL_CFLAGS)
|
||||||
subrelayd_CFLAGS = -Wall -Wextra -pedantic -std=c99
|
subrelayd_CFLAGS = -Wall -Wextra -pedantic -std=c99
|
||||||
subrelayd_LDADD = $(CURL_LIBS)
|
subrelayd_LDADD = $(CURL_LIBS)
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# shell CLI for control daemon
|
||||||
# subrelay-shell CLI Tool
|
sbrlctrl_SOURCES = \
|
||||||
# ------------------------------------------------------------------------------
|
sbctrl.c
|
||||||
subrelay_shell_SOURCES = \
|
|
||||||
subrelay-shell.c
|
|
||||||
|
|
||||||
subrelay_shell_CFLAGS = -Wall -Wextra -pedantic -std=c99
|
sbrlctrl_CFLAGS = -Wall -Wextra -pedantic -std=c99
|
||||||
subrelay_shell_CPPFLAGS = -I$(top_srcdir)/include -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE
|
sbrlctrl_CPPFLAGS = -I$(top_srcdir)/include -D_POSIX_C_SOURCE=200809L -D_DEFAULT_SOURCE
|
||||||
|
|||||||
143
src/sbctrl.c
Normal file
143
src/sbctrl.c
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* sbctrl: maillist daemon control utility (main entry)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
|
#define MAXCMD_LEN 1024
|
||||||
|
#define READBUF_LEN 2048
|
||||||
|
#define DEFAULT_SOCKET "/var/run/subrelay/subrelayd.sock"
|
||||||
|
|
||||||
|
static void print_usage(const char *progname)
|
||||||
|
{
|
||||||
|
printf("Subrelay control utility\n");
|
||||||
|
printf("Usage: %s -s <socket_path> <command> [args...]\n\n", progname);
|
||||||
|
printf("Arguments:\n");
|
||||||
|
printf(" -s|--socket <path> Path to subrelay local socket\n");
|
||||||
|
printf(" -h|--help Print help\n");
|
||||||
|
printf("Commands:\n");
|
||||||
|
printf(" ADD <email> Directly subscribe an email address\n");
|
||||||
|
printf(" DEL <email> Unsubscribe an email address\n");
|
||||||
|
printf(" LIST List all current subscribers\n");
|
||||||
|
printf(" STATUS Show daemon operational status\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *socket_path = DEFAULT_SOCKET;
|
||||||
|
char cmd_buf[MAXCMD_LEN];
|
||||||
|
size_t used = 0;
|
||||||
|
int opt;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
int option_index = 0;
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"help", no_argument, NULL, 'h'},
|
||||||
|
{"socket", required_argument, NULL, 's'},
|
||||||
|
{NULL, 0, NULL, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
if((opt = getopt_long(argc, argv, "hs:", long_options, &option_index)) == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch(opt) {
|
||||||
|
case 'h': print_usage(argv[0]); return 0; break;
|
||||||
|
case 's': socket_path = optarg; break;
|
||||||
|
default: print_usage(argv[0]); return EXIT_FAILURE; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind >= argc) {
|
||||||
|
fprintf(stderr, "error: command required\n");
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build command string from remaining arguments */
|
||||||
|
cmd_buf[0] = '\0';
|
||||||
|
for (int i = optind; i < argc; i++) {
|
||||||
|
size_t len = strlen(argv[i]);
|
||||||
|
size_t extra = len + (i < argc - 1 ? 1 : 0); /* argument + optional space */
|
||||||
|
|
||||||
|
/* Leave room for the final newline and the terminating nil */
|
||||||
|
if (extra > sizeof(cmd_buf) - used - 2) {
|
||||||
|
fprintf(stderr, "error: command or arguments too long.\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(cmd_buf + used, argv[i], len);
|
||||||
|
used += len;
|
||||||
|
|
||||||
|
if (i < argc - 1) cmd_buf[used++] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_buf[used++] = '\n';
|
||||||
|
cmd_buf[used] = '\0';
|
||||||
|
|
||||||
|
/* Connect to subrelayd UNIX domain socket */
|
||||||
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("error opening socket");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
if(strlen(socket_path) > sizeof(addr.sun_path)) {
|
||||||
|
fprintf(stderr, "Socket pathname is too long.\n");
|
||||||
|
close(fd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
} else strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
||||||
|
fprintf(stderr, "error: cannot connect to subrelayd at '%s': %s\n",
|
||||||
|
socket_path, strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send command */
|
||||||
|
if (write(fd, cmd_buf, strlen(cmd_buf)) < 0) {
|
||||||
|
perror("error writing command to socket");
|
||||||
|
close(fd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and print daemon response */
|
||||||
|
char resp[READBUF_LEN];
|
||||||
|
ssize_t bytes;
|
||||||
|
|
||||||
|
while ((bytes = read(fd, resp, sizeof resp)) > 0) {
|
||||||
|
if (fwrite(resp, 1, (size_t)bytes, stdout) != (size_t)bytes) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ignore read errors -- non critical */
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@ -1,86 +0,0 @@
|
|||||||
/* src/subrelay-shell/main.c - Management CLI tool */
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
|
|
||||||
static void print_usage(const char *progname)
|
|
||||||
{
|
|
||||||
printf("Subrelay Management Shell\n");
|
|
||||||
printf("Usage: %s -s <socket_path> <command> [args...]\n\n", progname);
|
|
||||||
printf("Commands:\n");
|
|
||||||
printf(" ADD <email> Directly subscribe an email address\n");
|
|
||||||
printf(" DEL <email> Unsubscribe an email address\n");
|
|
||||||
printf(" LIST List all current subscribers\n");
|
|
||||||
printf(" STATUS Show daemon operational status\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char *socket_path = "/var/run/subrelay/subrelayd.sock";
|
|
||||||
int opt;
|
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "s:h")) != -1) {
|
|
||||||
switch (opt) {
|
|
||||||
case 's': socket_path = optarg; break;
|
|
||||||
case 'h': print_usage(argv[0]); return EXIT_SUCCESS;
|
|
||||||
default: print_usage(argv[0]); return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optind >= argc) {
|
|
||||||
fprintf(stderr, "error: command required\n");
|
|
||||||
print_usage(argv[0]);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build command string from remaining arguments */
|
|
||||||
char cmd_buf[1024];
|
|
||||||
cmd_buf[0] = '\0';
|
|
||||||
|
|
||||||
for (int i = optind; i < argc; i++) {
|
|
||||||
strcat(cmd_buf, argv[i]);
|
|
||||||
if (i < argc - 1) strcat(cmd_buf, " ");
|
|
||||||
}
|
|
||||||
strcat(cmd_buf, "\n");
|
|
||||||
|
|
||||||
/* Connect to subrelayd UNIX domain socket */
|
|
||||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (fd < 0) {
|
|
||||||
perror("error opening socket");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sockaddr_un addr;
|
|
||||||
memset(&addr, 0, sizeof(addr));
|
|
||||||
addr.sun_family = AF_UNIX;
|
|
||||||
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
|
||||||
|
|
||||||
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
|
||||||
fprintf(stderr, "error: cannot connect to subrelayd at '%s': %s\n",
|
|
||||||
socket_path, strerror(errno));
|
|
||||||
close(fd);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send command */
|
|
||||||
if (write(fd, cmd_buf, strlen(cmd_buf)) < 0) {
|
|
||||||
perror("error writing command to socket");
|
|
||||||
close(fd);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read and print daemon response */
|
|
||||||
char resp[2048];
|
|
||||||
ssize_t bytes;
|
|
||||||
while ((bytes = read(fd, resp, sizeof(resp) - 1)) > 0) {
|
|
||||||
resp[bytes] = '\0';
|
|
||||||
printf("%s", resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
close(fd);
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user