Mercurial > irccd
changeset 941:e43ccb1f0ace
irccdctl: add basics commands
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 14 Jan 2021 17:44:48 +0100 |
parents | 94cae3129870 |
children | d6febe682db7 |
files | .hgignore Makefile irccdctl/main.c lib/irccd/irccd.c lib/irccd/irccd.h lib/irccd/peer.c lib/irccd/transport.c |
diffstat | 7 files changed, 739 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgignore Thu Jan 14 10:46:41 2021 +0100 +++ b/.hgignore Thu Jan 14 17:44:48 2021 +0100 @@ -18,7 +18,8 @@ ^extern/libcompat/trylib$ # executables. -irccd/irccd +^irccd/irccd$ +^irccdctl/irccdctl$ # temporary files. ^lib/irccd/config\.h$
--- a/Makefile Thu Jan 14 10:46:41 2021 +0100 +++ b/Makefile Thu Jan 14 17:44:48 2021 +0100 @@ -30,6 +30,11 @@ IRCCD_OBJS= ${IRCCD_SRCS:.c=.o} IRCCD_DEPS= ${IRCCD_SRCS:.c=.d} +IRCCDCTL= irccdctl/irccdctl +IRCCDCTL_SRCS= irccdctl/main.c +IRCCDCTL_OBJS= ${IRCCDCTL_SRCS:.c=.o} +IRCCDCTL_DEPS= ${IRCCDCTL_SRCS:.c=.d} + LIBCOMPAT= extern/libcompat/libirccd-compat.a ifeq (${WITH_JS},yes) @@ -96,7 +101,7 @@ LIBS+= -l ssl -l crypto endif -all: ${IRCCD} +all: ${IRCCD} ${IRCCDCTL} .c.o: ${CMD.cc} @@ -134,6 +139,9 @@ ${IRCCD}: ${IRCCD_OBJS} ${LIBCOMPAT} ${LIBDUKTAPE} ${LIBIRCCD} ${CMD.ccld} +${IRCCDCTL}: ${IRCCDCTL_OBJS} + ${CMD.ccld} + # Unit tests. tests/test-%.o: tests/test-%.c ${CMD.cc}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/irccdctl/main.c Thu Jan 14 17:44:48 2021 +0100 @@ -0,0 +1,296 @@ +/* + * main.c -- irccdctl(1) main file + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/socket.h> +#include <sys/un.h> +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdnoreturn.h> +#include <string.h> +#include <unistd.h> + +#include <stdio.h> + +#include <irccd/limits.h> +#include <irccd/util.h> + +static bool verbose; +static int sock; +static struct sockaddr_un sockaddr = { + .sun_family = PF_LOCAL, + .sun_path = "/tmp/irccd.sock" +}; +static char in[IRC_BUF_MAX]; +static char out[IRC_BUF_MAX]; + +static char * +poll(void) +{ + static char ret[IRC_BUF_MAX]; + char *nl; + + while (!(nl = strstr(in, "\n"))) { + char buf[IRC_BUF_MAX] = {0}; + + if (recv(sock, buf, sizeof (buf) - 1, 0) <= 0) + err(1, "abort"); + if (strlcat(in, buf, sizeof (in)) >= sizeof (in)) + errc(1, EMSGSIZE, "abort"); + } + + *nl = '\0'; + strlcpy(ret, in, sizeof (ret)); + memmove(in, nl + 1, sizeof (in) - (nl - in) - 1); + + return ret; +} + +static void +dial(void) +{ + const struct timeval tv = { + .tv_sec = 30 + }; + + if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) + err(1, "socket"); + if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof (tv)) < 0 || + setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof (tv)) < 0) + err(1, "setsockopt"); + if (connect(sock, (const struct sockaddr *)&sockaddr, SUN_LEN(&sockaddr)) < 0) + err(1, "connect"); +} + +static void +check(void) +{ + /* Ensure we're talking to irccd. */ + int major, minor, patch; + + if ((sscanf(poll(), "IRCCD %d.%d.%d", &major, &minor, &patch) != 3)) + errx(1, "abort: not irccd instance"); + if (verbose) + printf("connected to irccd %d.%d.%d\n", major, minor, patch); +} + +static void +req(const char *fmt, ...) +{ + char buf[IRC_BUF_MAX]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(buf, sizeof (buf), fmt, ap); + va_end(ap); + + if (strlcat(out, buf, sizeof (out)) >= sizeof (out) || + strlcat(out, "\n", sizeof (out)) >= sizeof (out)) + errc(1, EMSGSIZE, "abort"); + + while (out[0]) { + ssize_t ns, len; + + len = strlen(out); + + if ((ns = send(sock, out, len, MSG_NOSIGNAL)) <= 0) + err(1, "send"); + + if (ns >= len) + memset(out, 0, sizeof (out)); + else + memmove(out, out + ns, sizeof (out) - ns); + } +} + +static void +ok(void) +{ + const char *response = poll(); + + if (strcmp(response, "OK") != 0) + errx(1, "abort: %s", response); +} + +static void +cmd_server_list(int argc, char **argv) +{ + (void)argc; + (void)argv; + + char *list; + + req("SERVER-LIST"); + + if (strncmp(list = poll(), "OK ", 3) != 0) + errx(1, "failed to retrieve server list"); + + /* Skip "OK " */ + list += 3; + + /* Since list is separated by spaces, just convert them to \n */ + for (char *p; (p = strchr(list, ' ')); ) + *p = '\n'; + + puts(list); +} + +static void +cmd_server_message(int argc, char **argv) +{ + (void)argc; + + req("SERVER-MESSAGE %s %s %s", argv[0], argv[1], argv[2]); + ok(); +} + +static void +cmd_server_me(int argc, char **argv) +{ + (void)argc; + + req("SERVER-ME %s %s %s", argv[0], argv[1], argv[2]); + ok(); +} + +static void +cmd_server_mode(int argc, char **argv) +{ +#if 0 + req("MODE %s %s %s%c%s%c%s%c%s", argv[0], argv[1], argv[2], + argc >= 4 ? ' ', argv[3] : "", + argc >= 5 ? ' ', argv[4] : "", + argc >= 6 ? ' ', argv[5] : ""); + ok(); +#endif +} + +static void +cmd_server_nick(int argc, char **argv) +{ + req("SERVER-NICK %s %s", argv[0], argv[1]); + ok(); +} + +static void +cmd_server_notice(int argc, char **argv) +{ + req("SERVER-NOTICE %s %s %s", argv[0], argv[1], argv[2]); + ok(); +} + +static void +cmd_server_part(int argc, char **argv) +{ + /* Let's advertise irccd a bit. */ + req("SERVER-PART %s %s %s", argv[0], argv[1], + argc >= 3 ? argv[2] : "irccd is shutting down"); + ok(); +} + +static void +cmd_server_topic(int argc, char **argv) +{ + req("SERVER-TOPIC %s %s %s", argv[0], argv[1], argv[2]); + ok(); +} + +static const struct cmd { + const char *name; + unsigned int minargs; + unsigned int maxargs; + void (*exec)(int, char **); +} cmds[] = { + /* name min max exec */ + { "server-list", 0, 0, cmd_server_list }, + { "server-me", 3, 3, cmd_server_me }, + { "server-message", 3, 3, cmd_server_message }, + { "server-mode", 3, 6, cmd_server_mode }, + { "server-nick", 2, 2, cmd_server_nick }, + { "server-notice", 3, 3, cmd_server_notice }, + { "server-part", 3, 3, cmd_server_part }, + { "server-topic", 3, 3, cmd_server_topic } +}; + +static int +cmp_cmd(const void *d1, const void *d2) +{ + return strcmp(d1, ((const struct cmd *)d2)->name); +} + +static const struct cmd * +find_cmd(const char *name) +{ + return bsearch(name, cmds, IRC_UTIL_SIZE(cmds), sizeof (cmds[0]), cmp_cmd); +} + +static void +run(int argc, char **argv) +{ + const struct cmd *c; + + if (!(c = find_cmd(argv[0]))) + errx(1, "abort: command not found"); + + --argc; + ++argv; + + if (argc < c->minargs || argc > c->maxargs) + errx(1, "abort: invalid number of arguments"); + + c->exec(argc, argv); +} + +static noreturn void +usage(void) +{ + /* TODO: getprogname() */ + fprintf(stderr, "usage: irccdctl [-v] [-s sock] command [arguments...]\n"); + exit(1); +} + +int +main(int argc, char **argv) +{ + for (int ch; (ch = getopt(argc, argv, "s:v")) != -1; ) { + switch (ch) { + case 's': + strlcpy(sockaddr.sun_path, optarg, sizeof (sockaddr.sun_path)); + break; + case 'v': + verbose = true; + break; + default: + break; + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) + usage(); + + dial(); + check(); + run(argc, argv); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/irccd.c Thu Jan 14 17:44:48 2021 +0100 @@ -0,0 +1,310 @@ +/* + * irccd.c -- main irccd object + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <err.h> +#include <poll.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "event.h" +#include "irccd.h" +#include "log.h" +#include "plugin.h" +#include "server.h" +#include "peer.h" +#include "transport.h" +#include "util.h" + +/* TODO: TMP */ +#include <stdio.h> + +#define APPEND(a, l, o, f) \ +do { \ + a = irc_util_reallocarray(a, ++l, sizeof (*o)); \ + memcpy(&a[l - 1], o, sizeof (*o)); \ + qsort(a, l, sizeof (*o), f); \ +} while (0) + +#define REMOVE(a, l, f) \ +do { \ + if (--l == 0) { \ + free(a); \ + a = NULL; \ + } else { \ + qsort(a, l + 1, sizeof (*a), f); \ + a = irc_util_reallocarray(a, --l, sizeof (*a)); \ + } \ +} while (0) + +struct pkg { + struct pollfd *fds; + size_t fdsz; +}; + +struct defer { + void (*exec)(void *); + void (*data); +}; + +struct irc irc; + +static int pipes[2]; + +static int +cmp_server(const void *d1, const void *d2) +{ + return strcmp( + ((const struct irc_server *)d1)->name, + ((const struct irc_server *)d2)->name + ); +} + +static int +cmp_plugin(const void *d1, const void *d2) +{ + return strcmp( + ((const struct irc_plugin *)d1)->name, + ((const struct irc_plugin *)d2)->name + ); +} + +static int +cmp_peer(const void *d1, const void *d2) +{ + return ((const struct irc_peer *)d2)->fd - ((const struct irc_peer *)d1)->fd; +} + +static int +cmp_server_name(const void *d1, const void *d2) +{ + return strcmp(d1, ((const struct irc_server *)d2)->name); +} + +static int +cmp_plugin_name(const void *d1, const void *d2) +{ + return strcmp(d1, ((const struct irc_plugin *)d2)->name); +} + +static struct pkg +prepare(void) +{ + struct pkg pkg = {0}; + size_t i = 0; + + pkg.fdsz += 1; /* pipe */ + pkg.fdsz += 1; /* transport fd */ + pkg.fdsz += irc.serversz; /* servers */ + pkg.fdsz += irc.peersz; /* transport peers */ + + pkg.fds = irc_util_calloc(pkg.fdsz, sizeof (*pkg.fds)); + + /* pipe */ + pkg.fds[i].fd = pipes[0]; + pkg.fds[i++].events = POLLIN; + + /* transport */ + irc_transport_prepare(&pkg.fds[i++]); + + for (size_t p = 0; p < irc.peersz; ++p) + irc_peer_prepare(&irc.peers[p], &pkg.fds[i++]); + + for (size_t s = 0; s < irc.serversz; ++s) + irc_server_prepare(&irc.servers[s], &pkg.fds[i++]); + + return pkg; +} + +static void +invoke(const struct irc_event *ev) +{ + for (size_t i = 0; i < irc.pluginsz; ++i) + irc_plugin_handle(&irc.plugins[i], ev); +} + +static void +pipe_flush(struct pollfd *fd) +{ + struct defer df = {0}; + + if (fd->fd != pipes[0] || !(fd->revents & POLLIN)) + return; + + if (read(fd->fd, &df, sizeof (df)) != sizeof (df)) + err(1, "read"); + + df.exec(df.data); +} + +static void +process(struct pkg *pkg) +{ + + if (poll(pkg->fds, pkg->fdsz, 1000) < 0) + err(1, "poll"); + + /* + * We can't to what file descriptors belong to so pass every file to + * all services and they must check if they are associated to it or + * not. + */ + for (size_t i = 0; i < pkg->fdsz; ++i) { + struct irc_peer peer; + + pipe_flush(&pkg->fds[i]); + + for (size_t s = 0; s < irc.serversz; ++s) + irc_server_flush(&irc.servers[s], &pkg->fds[i]); + + /* Accept new transport client. */ + if (irc_transport_flush(&pkg->fds[i], &peer)) + APPEND(irc.peers, irc.peersz, &peer, cmp_peer); + + /* Flush clients. */ + for (size_t p = 0; p < irc.peersz; ++p) { + if (!irc_peer_flush(&irc.peers[p], &pkg->fds[i])) { + irc_peer_finish(&irc.peers[p]); + REMOVE(irc.peers, irc.peersz, cmp_peer); + } + } + } + + /* + * For every server, poll any kind of new event and pass them to the + * plugin unless the rules explicitly disallow us to do so. + */ + for (size_t s = 0; s < irc.serversz; ++s) { + struct irc_event ev; + + while (irc_server_poll(&irc.servers[s], &ev)) + invoke(&ev); + } +} + +static void +clean(struct pkg *pkg) +{ + free(pkg->fds); +} + +void +irc_init(void) +{ + irc_log_to_console(); + + if (pipe(pipes) < 0) + err(1, "pipe"); +} + +void +irc_add_server(const struct irc_server *s) +{ + assert(s); + + APPEND(irc.servers, irc.serversz, s, cmp_server); + + irc_server_connect(&irc.servers[irc.serversz - 1]); +} + +struct irc_server * +irc_find_server(const char *name) +{ + return bsearch(name, irc.servers, irc.serversz, sizeof (*irc.servers), + cmp_server_name); +} + +void +irc_del_server(const char *name) +{ + struct irc_server *s; + + if (!(s = irc_find_server(name))) + return; + + irc_server_disconnect(s); + + /* Don't forget to notify plugins. */ + invoke(&(const struct irc_event) { + .type = IRC_EVENT_DISCONNECT, + .server = s + }); + + /* Finally remove from array. */ + REMOVE(irc.servers, irc.serversz, cmp_server); +} + +void +irc_add_plugin(const struct irc_plugin *p) +{ + assert(p); + + APPEND(irc.plugins, irc.pluginsz, p, cmp_plugin); + + irc_log_info("plugin %s: %s", p->name, p->description); + irc_log_info("plugin %s: version %s, from %s (%s license)", p->name, + p->version, p->author, p->license); + + irc_plugin_load(&irc.plugins[irc.pluginsz - 1]); +} + +struct irc_plugin * +irc_find_plugin(const char *name) +{ + return bsearch(name, irc.plugins, irc.pluginsz, sizeof (*irc.plugins), + cmp_plugin_name); +} + +void +irc_del_plugin(const char *name) +{ + struct irc_plugin *p; + + if (!(p = irc_find_plugin(name))) + return; + + irc_plugin_unload(p); + irc_plugin_finish(p); + + REMOVE(irc.plugins, irc.pluginsz, cmp_plugin); +} + +void +irc_post(void (*exec)(void *), void *data) +{ + struct defer df = { + .exec = exec, + .data = data + }; + + if (write(pipes[1], &df, sizeof (df)) != sizeof (df)) + err(1, "write"); +} + +void +irc_run(void) +{ + struct pkg pkg; + + for (;;) { + pkg = prepare(); + process(&pkg); + clean(&pkg); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/irccd.h Thu Jan 14 17:44:48 2021 +0100 @@ -0,0 +1,64 @@ +/* + * irccd.h -- main irccd object + * + * Copyright (c) 2013-2021 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef IRCCD_H +#define IRCCD_H + +#include <stddef.h> + +struct irc_server; +struct irc_plugin; +struct irc_peer; + +extern struct irc { + struct irc_peer *peers; + size_t peersz; + struct irc_plugin *plugins; + size_t pluginsz; + struct irc_server *servers; + size_t serversz; +} irc; + +void +irc_init(void); + +void +irc_add_server(const struct irc_server *); + +struct irc_server * +irc_find_server(const char *); + +void +irc_del_server(const char *); + +void +irc_add_plugin(const struct irc_plugin *); + +struct irc_plugin * +irc_find_plugin(const char *); + +void +irc_del_plugin(const char *); + +void +irc_post(void (*)(void *), void *); + +void +irc_run(void); + +#endif /* !IRCCD_H */
--- a/lib/irccd/peer.c Thu Jan 14 10:46:41 2021 +0100 +++ b/lib/irccd/peer.c Thu Jan 14 17:44:48 2021 +0100 @@ -75,11 +75,19 @@ return s; } +static int +ok(struct irc_peer *p) +{ + irc_peer_send(p, "OK"); + + return 0; +} + /* * MESSAGE server channel message */ static int -cmd_message(struct irc_peer *p, char *line) +cmd_server_message(struct irc_peer *p, char *line) { const char *args[3] = {0}; struct irc_server *s; @@ -91,14 +99,14 @@ irc_server_message(s, args[1], args[2]); - return 0; + return ok(p); } /* * ME server channel message */ static int -cmd_me(struct irc_peer *p, char *line) +cmd_server_me(struct irc_peer *p, char *line) { const char *args[3] = {0}; struct irc_server *s; @@ -110,14 +118,14 @@ irc_server_me(s, args[1], args[2]); - return 0; + return ok(p); } /* * MODE server channel mode [limit] [user] [mask] */ static int -cmd_mode(struct irc_peer *p, char *line) +cmd_server_mode(struct irc_peer *p, char *line) { const char *args[6] = {0}; struct irc_server *s; @@ -133,14 +141,14 @@ args[5][0] ? args[5] : NULL ); - return 0; + return ok(p); } /* * NOTICE server channel message */ static int -cmd_notice(struct irc_peer *p, char *line) +cmd_server_notice(struct irc_peer *p, char *line) { const char *args[3] = {0}; struct irc_server *s; @@ -152,14 +160,14 @@ irc_server_notice(s, args[1], args[2]); - return 0; + return ok(p); } /* * INVITE server channel target */ static int -cmd_invite(struct irc_peer *p, char *line) +cmd_server_invite(struct irc_peer *p, char *line) { const char *args[3] = {0}; struct irc_server *s; @@ -171,14 +179,14 @@ irc_server_invite(s, args[1], args[2]); - return 0; + return ok(p); } /* * JOIN server channel [password] */ static int -cmd_join(struct irc_peer *p, char *line) +cmd_server_join(struct irc_peer *p, char *line) { const char *args[3] = {0}; struct irc_server *s; @@ -190,14 +198,14 @@ irc_server_join(s, args[1], args[2][0] ? args[2] : NULL); - return 0; + return ok(p); } /* * KICK server channel target [reason] */ static int -cmd_kick(struct irc_peer *p, char *line) +cmd_server_kick(struct irc_peer *p, char *line) { const char *args[4] = {0}; struct irc_server *s; @@ -209,6 +217,23 @@ irc_server_kick(s, args[1], args[2], args[3][0] ? args[3] : NULL); + return ok(p); +} + +static int +cmd_server_list(struct irc_peer *p, char *line) +{ + char out[IRC_BUF_MAX] = "OK "; + + for (size_t i = 0; i < irc.serversz; ++i) { + if (strlcat(out, irc.servers[i].name, sizeof (out)) >= sizeof (out)) + return EMSGSIZE; + if (i + 1 < irc.serversz && strlcat(out, " ", sizeof (out)) >= sizeof (out)) + return EMSGSIZE; + } + + irc_peer_send(p, out); + return 0; } @@ -216,7 +241,7 @@ * PART server channel [reason] */ static int -cmd_part(struct irc_peer *p, char *line) +cmd_server_part(struct irc_peer *p, char *line) { const char *args[3] = {0}; struct irc_server *s; @@ -224,18 +249,18 @@ if (parse(line, args, 3) < 2) return EINVAL; if (!(s = require_server(p, args[0]))) - return -10; + return 0; irc_server_part(s, args[1], args[2][0] ? args[2] : NULL); - return 0; + return ok(p); } /* * TOPIC server channel topic */ static int -cmd_topic(struct irc_peer *p, char *line) +cmd_server_topic(struct irc_peer *p, char *line) { const char *args[3] = {0}; struct irc_server *s; @@ -247,22 +272,23 @@ irc_server_topic(s, args[1], args[2]); - return 0; + return ok(p); } static const struct cmd { const char *name; int (*call)(struct irc_peer *, char *); } cmds[] = { - { "INVITE", cmd_invite }, - { "JOIN", cmd_join }, - { "KICK", cmd_kick }, - { "ME", cmd_me }, - { "MESSAGE", cmd_message }, - { "MODE", cmd_mode }, - { "NOTICE", cmd_notice }, - { "PART", cmd_part }, - { "TOPIC", cmd_topic }, + { "SERVER-INVITE", cmd_server_invite }, + { "SERVER-JOIN", cmd_server_join }, + { "SERVER-KICK", cmd_server_kick }, + { "SERVER-LIST", cmd_server_list }, + { "SERVER-ME", cmd_server_me }, + { "SERVER-MESSAGE", cmd_server_message }, + { "SERVER-MODE", cmd_server_mode }, + { "SERVER-NOTICE", cmd_server_notice }, + { "SERVER-PART", cmd_server_part }, + { "SERVER-TOPIC", cmd_server_topic }, }; static int @@ -271,7 +297,7 @@ const char *key = d1; const struct cmd *cmd = d2; - return strncmp(cmd->name, key, strlen(cmd->name)); + return strncmp(key, cmd->name, strlen(cmd->name)); } static const struct cmd * @@ -288,10 +314,8 @@ if (!c) irc_peer_send(p, "command not found"); - else if ((er = c->call(p, line)) != 0 && er != -1) + else if ((er = c->call(p, line)) != 0) irc_peer_send(p, "%s", strerror(errno)); - else - irc_peer_send(p, "OK"); } static void
--- a/lib/irccd/transport.c Thu Jan 14 10:46:41 2021 +0100 +++ b/lib/irccd/transport.c Thu Jan 14 17:44:48 2021 +0100 @@ -40,12 +40,14 @@ { assert(path); - /* Silently remove the file first. */ + addr.sun_family = PF_LOCAL; + if (strlcpy(addr.sun_path, path, sizeof (addr.sun_path)) >= sizeof (addr.sun_path)) { errno = ENAMETOOLONG; goto err; } + /* Silently remove the file first. */ unlink(addr.sun_path); if ((fd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)