Mercurial > irccd
view lib/irccd/hook.c @ 1183:1845a0509a93
misc: update copyright years
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 01 Feb 2023 12:43:11 +0100 |
parents | f06e9761cc90 |
children | 67fa43998a91 |
line wrap: on
line source
/* * hook.c -- irccd hooks * * Copyright (c) 2013-2023 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/wait.h> #include <assert.h> #include <errno.h> #include <stdarg.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include "event.h" #include "hook.h" #include "log.h" #include "server.h" #include "util.h" static char ** alloc(const struct irc_hook *h, size_t n, ...) { char **ret; va_list ap; ret = irc_util_calloc(n + 2, sizeof (*ret)); ret[0] = (char *)h->path; va_start(ap, n); for (size_t i = 0; i < n; ++i) ret[i + 1] = va_arg(ap, char *); va_end(ap); return ret; } static char ** alloc_mode(const struct irc_hook *h, const struct irc_event *ev) { size_t n = 6; char **ret; /* Ret contains now 6 values. */ ret = alloc(h, 5, "onMode", ev->server->name, ev->mode.origin, ev->mode.channel, ev->mode.mode); for (char **mode = ev->mode.args; *mode; ++mode) { ret = irc_util_reallocarray(ret, n + 1, sizeof (char *)); ret[n++] = *mode; }; ret = irc_util_reallocarray(ret, n + 1, sizeof (char *)); ret[n] = NULL; return ret; } static char ** make_args(const struct irc_hook *h, const struct irc_event *ev) { char **ret; switch (ev->type) { case IRC_EVENT_CONNECT: ret = alloc(h, 2, "onConnect", ev->server->name); break; case IRC_EVENT_DISCONNECT: ret = alloc(h, 2, "onDisconnect", ev->server->name); break; case IRC_EVENT_INVITE: ret = alloc(h, 4, "onInvite", ev->server->name, ev->invite.origin, ev->invite.channel); break; case IRC_EVENT_JOIN: ret = alloc(h, 4, "onJoin", ev->server->name, ev->join.origin, ev->join.channel); break; case IRC_EVENT_KICK: ret = alloc(h, 6, "onKick", ev->server->name, ev->kick.origin, ev->kick.channel, ev->kick.target, ev->kick.reason); break; case IRC_EVENT_ME: ret = alloc(h, 5, "onMe", ev->server->name, ev->message.origin, ev->message.channel, ev->message.message); break; case IRC_EVENT_MESSAGE: ret = alloc(h, 5, "onMessage", ev->server->name, ev->message.origin, ev->message.channel, ev->message.message); break; case IRC_EVENT_MODE: ret = alloc_mode(h, ev); break; case IRC_EVENT_NICK: ret = alloc(h, 4, "onNick", ev->server->name, ev->nick.origin, ev->nick.nickname); break; case IRC_EVENT_NOTICE: ret = alloc(h, 5, "onNotice", ev->server->name, ev->notice.origin, ev->notice.channel, ev->notice.notice); break; case IRC_EVENT_PART: ret = alloc(h, 5, "onPart", ev->server->name, ev->part.origin, ev->part.channel, ev->part.reason); break; case IRC_EVENT_TOPIC: ret = alloc(h, 5, "onTopic", ev->server->name, ev->topic.origin, ev->topic.channel, ev->topic.topic); break; default: return NULL; } return ret; } struct irc_hook * irc_hook_new(const char *name, const char *path) { assert(name); assert(path); struct irc_hook *h; h = irc_util_malloc(sizeof (*h)); irc_util_strlcpy(h->name, name, sizeof (h->name)); irc_util_strlcpy(h->path, path, sizeof (h->path)); return h; } void irc_hook_invoke(struct irc_hook *h, const struct irc_event *ev) { assert(h); assert(ev); char **args; pid_t child; if (!(args = make_args(h, ev))) return; switch ((child = fork())) { case -1: irc_log_warn("hook %s: %s", h->name, strerror(errno)); break; case 0: execv(h->path, args); irc_log_warn("hook %s: %s", h->name, strerror(errno)); exit(1); break; default: /* We wait for signal handler using SIGCHLD. */ break; } free(args); } void irc_hook_finish(struct irc_hook *h) { assert(h); free(h); }