diff irccdctl/main.c @ 975:5ffc8350e84b

irccdctl: add support for rule editing
author David Demelier <markand@malikania.fr>
date Tue, 09 Feb 2021 13:00:32 +0100
parents 342fb90f2512
children 489d80468925
line wrap: on
line diff
--- a/irccdctl/main.c	Sun Feb 07 14:36:28 2021 +0100
+++ b/irccdctl/main.c	Tue Feb 09 13:00:32 2021 +0100
@@ -27,12 +27,13 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <stdnoreturn.h>
 #include <string.h>
 #include <unistd.h>
 
-#include <stdio.h>
+#include <ketopt.h>
 
 #include <irccd/limits.h>
 #include <irccd/util.h>
@@ -488,6 +489,131 @@
 }
 
 static void
+cmd_rule_add(int argc, char **argv)
+{
+	ketopt_t ko = KETOPT_INIT;
+	FILE *fp;
+	char out[IRC_BUF_LEN];
+
+	if (!(fp = fmemopen(out, sizeof (out) - 1, "w")))
+		err(1, "fmemopen");
+
+	/* TODO: invalid option. */
+	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "c:e:i:o:p:s:", NULL)) != -1; )
+		fprintf(fp, "%c=%s ", ch, ko.arg);
+
+	argc -= ko.ind;
+	argv += ko.ind;
+
+	if (argc < 1)
+		errx(1, "missing accept or drop rule action");
+
+	fprintf(fp, "%s", argv[0]);
+
+	if (ferror(fp) || feof(fp))
+		err(1, "fprintf");
+
+	fclose(fp);
+	req("RULE-ADD %s %s", argv[0], out);
+	ok();
+}
+
+static void
+cmd_rule_edit(int argc, char **argv)
+{
+	ketopt_t ko = KETOPT_INIT;
+	FILE *fp;
+	char out[IRC_BUF_LEN];
+
+	if (!(fp = fmemopen(out, sizeof (out) - 1, "w")))
+		err(1, "fmemopen");
+
+	/* TODO: invalid option. */
+	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "a:C:c:E:e:O:o:P:p:S:s:", NULL)) != -1; ) {
+		if (ch == 'a')
+			fprintf(fp, "a=%s ", ko.arg);
+		else
+			fprintf(fp, "%c%c%s ", tolower(ch), isupper(ch) ? '-' : '+', ko.arg);
+	}
+
+	argc -= ko.ind;
+	argv += ko.ind;
+
+	if (argc < 1)
+		errx(1, "missing rule index");
+
+	if (ferror(fp) || feof(fp))
+		err(1, "fprintf");
+
+	fclose(fp);
+	req("RULE-EDIT %s %s", argv[0], out);
+	ok();
+}
+
+/*
+ * Response:
+ *
+ *     OK <n>
+ *     accept
+ *     server1 server2 server3 ...
+ *     channel1 channel2 channel3 ...
+ *     origin1 origin2 origin3 ...
+ *     plugin1 plugin2 plugin3 ...
+ *     event1 event2 plugin3 ...
+ *     (repeat for every rule in <n>)
+ */
+static void
+cmd_rule_list(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+
+	size_t num = 0;
+
+	req("RULE-LIST");
+
+	if (sscanf(ok(), "%zu", &num) != 1)
+		errx(1, "could not retrieve rule list");
+
+	for (size_t i = 0; i < num; ++i) {
+		printf("%-16s: %zu\n", "index", i);
+		printf("%-16s: %s\n", "action", poll());
+		printf("%-16s: %s\n", "servers", poll());
+		printf("%-16s: %s\n", "channels", poll());
+		printf("%-16s: %s\n", "origins", poll());
+		printf("%-16s: %s\n", "plugins", poll());
+		printf("%-16s: %s\n", "events", poll());
+		printf("\n");
+	}
+}
+
+static void
+cmd_rule_move(int argc, char **argv)
+{
+	(void)argc;
+
+	long long from, to;
+	const char *errstr;
+
+	if ((from = strtonum(argv[0], 0, LLONG_MAX, &errstr)) == 0 && errstr)
+		err(1, "%s", argv[0]);
+	if ((to = strtonum(argv[1], 0, LLONG_MAX, &errstr)) == 0 && errstr)
+		err(1, "%s", argv[1]);
+
+	req("RULE-MOVE %lld %lld", from, to);
+	ok();
+}
+
+static void
+cmd_rule_remove(int argc, char **argv)
+{
+	(void)argc;
+
+	req("RULE-REMOVE %s", argv[0]);
+	ok();
+}
+
+static void
 cmd_server_disconnect(int argc, char **argv)
 {
 	if (argc == 1)
@@ -679,6 +805,11 @@
 	{ "plugin-reload",      0,      1,      cmd_plugin_reload       },
 	{ "plugin-template",    1,      3,      cmd_plugin_template     },
 	{ "plugin-unload",      0,      1,      cmd_plugin_unload       },
+	{ "rule-add",          -1,     -1,      cmd_rule_add            },
+	{ "rule-edit",         -1,     -1,      cmd_rule_edit           },
+	{ "rule-list",          0,      0,      cmd_rule_list           },
+	{ "rule-move",          2,      2,      cmd_rule_move           },
+	{ "rule-remove",        1,      1,      cmd_rule_remove         },
 	{ "server-disconnect",  0,      1,      cmd_server_disconnect   },
 	{ "server-info",        1,      1,      cmd_server_info         },
 	{ "server-join",        2,      3,      cmd_server_join         },
@@ -716,7 +847,7 @@
 	--argc;
 	++argv;
 
-	if (argc < c->minargs || argc > c->maxargs)
+	if ((c->minargs != -1 && argc < c->minargs) || (c->minargs != -1 && argc > c->maxargs))
 		errx(1, "abort: invalid number of arguments");
 
 	c->exec(argc, argv);
@@ -725,16 +856,59 @@
 noreturn static void
 usage(void)
 {
-	fprintf(stderr, "usage: %s [-v] [-s sock] command [arguments...]\n", getprogname());
+	fprintf(stderr, "usage: %s [-v] [-s sock] command [options...] [arguments...]\n", getprogname());
+	exit(1);
+}
+
+noreturn static void
+help(void)
+{
+	fprintf(stderr, "usage: %s hook-add name path\n", getprogname());
+	fprintf(stderr, "       %s hook-list\n", getprogname());
+	fprintf(stderr, "       %s hook-remove id\n", getprogname());
+	fprintf(stderr, "       %s plugin-config id [variable [value]]\n", getprogname());
+	fprintf(stderr, "       %s plugin-info id\n", getprogname());
+	fprintf(stderr, "       %s plugin-list\n", getprogname());
+	fprintf(stderr, "       %s plugin-load name\n", getprogname());
+	fprintf(stderr, "       %s plugin-path [variable [value]]\n", getprogname());
+	fprintf(stderr, "       %s plugin-template [variable [value]]\n", getprogname());
+	fprintf(stderr, "       %s plugin-reload [plugin]\n", getprogname());
+	fprintf(stderr, "       %s plugin-unload [plugin]\n", getprogname());
+	fprintf(stderr, "       %s rule-add [-c channel] [-e event] [-i index] [-o origin] [-p plugin] [-s server] accept|drop\n", getprogname());
+	fprintf(stderr, "       %s rule-edit [-a accept|drop] [-c|C channel] [-e|E event] [-o|O origin] [-s|S server] index\n", getprogname());
+	fprintf(stderr, "       %s rule-list\n", getprogname());
+	fprintf(stderr, "       %s rule-move from to\n", getprogname());
+	fprintf(stderr, "       %s rule-remove index\n", getprogname());
+	fprintf(stderr, "       %s server-connect [-n nickname] [-r realname] [-u username] [-p port] id hostname\n", getprogname());
+	fprintf(stderr, "       %s server-disconnect [server]\n", getprogname());
+	fprintf(stderr, "       %s server-info server\n", getprogname());
+	fprintf(stderr, "       %s server-invite server target channel\n", getprogname());
+	fprintf(stderr, "       %s server-join server channel [password]\n", getprogname());
+	fprintf(stderr, "       %s server-kick server target channel [reason]\n", getprogname());
+	fprintf(stderr, "       %s server-list\n", getprogname());
+	fprintf(stderr, "       %s server-me server target message\n", getprogname());
+	fprintf(stderr, "       %s server-message server target message\n", getprogname());
+	fprintf(stderr, "       %s server-mode server target mode [limit] [user] [mask]\n", getprogname());
+	fprintf(stderr, "       %s server-nick server nickname\n", getprogname());
+	fprintf(stderr, "       %s server-notice server target message\n", getprogname());
+	fprintf(stderr, "       %s server-part server channel [reason]\n", getprogname());
+	fprintf(stderr, "       %s server-reconnect [server]\n", getprogname());
+	fprintf(stderr, "       %s server-topic server channel topic\n", getprogname());
+	fprintf(stderr, "       %s watch\n", getprogname());
 	exit(1);
 }
 
 int
 main(int argc, char **argv)
 {
+	ketopt_t ko = KETOPT_INIT;
+
 	setprogname("irccdctl");
 
-	for (int ch; (ch = getopt(argc, argv, "s:v")) != -1; ) {
+	--argc;
+	++argv;
+
+	for (int ch; (ch = ketopt(&ko, argc, argv, 0, "s:v", NULL)) != -1; ) {
 		switch (ch) {
 		case 's':
 			strlcpy(sockaddr.sun_path, optarg, sizeof (sockaddr.sun_path));
@@ -743,15 +917,18 @@
 			verbose = 1;
 			break;
 		default:
+			usage();
 			break;
 		}
 	}
 
-	argc -= optind;
-	argv += optind;
+	argc -= ko.ind;
+	argv += ko.ind;
 
 	if (argc < 1)
 		usage();
+	else if (strcmp(argv[0], "help") == 0)
+		help();
 
 	dial();
 	check();