/* * Copyright (c) 2026 Nakidai Perumenei * * Permission to use, copy, modify, and 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 "ircd.h" #include #include #define ARG(n) const char *n = va_arg(ap, const char *) #define M1(x, ...) #define M2(x, ...) ARG(x); M1(__VA_ARGS__) #define M3(x, ...) ARG(x); M2(__VA_ARGS__) #define M4(x, ...) ARG(x); M3(__VA_ARGS__) #define M5(x, ...) ARG(x); M4(__VA_ARGS__) #define M6(x, ...) ARG(x); M5(__VA_ARGS__) #define M7(x, ...) ARG(x); M6(__VA_ARGS__) #define GET_M(_0,_1,_2,_3,_4,_5,_6,_7,NAME,...) NAME #define ARGS(_0, ...) GET_M(_0,__VA_ARGS__,M7,M6,M5,M4,M3,M2,M1,M0,)(__VA_ARGS__,) /* * REPLY macro allows to write less boilerplate for each IRC reply * For example, * | REPLY(401, WRITE( * | ":%s 401 %s %s :No such nick/channel", * | hostname, * | getnick(peer), * | name * | ), name, _); * is unrolled into * | { * | const char *name = va_arg(ap, const char *); * | return WRITE( * | ":%s 401 %s %s :No such nick/channel", * | hostname, * | getnick(peer), * | name * | ); * | } * * Note the `_' argument, it's present as C doesn't support empty __VA_ARGS__ */ #define REPLY(n, action, ...) case n: { ARGS(,__VA_ARGS__); return action; } static int vreply(const struct Peer *peer, int number, va_list ap) { switch (number) { #define WRITE(...) writef(peer->fd, __VA_ARGS__) REPLY(1, WRITE( ":%s 001 %s Welcome to the Internet Relay Network %s!%s@%s", hostname, getnick(peer), getnick(peer), peer->user, peer->host ), _); REPLY(401, WRITE( ":%s 401 %s %s :No such nick/channel", hostname, getnick(peer), name ), name, _); REPLY(403, WRITE( ":%s 403 %s %s :No such channel", hostname, getnick(peer), channel ), channel, _); REPLY(405, WRITE( ":%s 405 %s %s :You have joined too many channels", hostname, getnick(peer), channel ), channel, _); REPLY(411, WRITE( ":%s 411 %s :No recipient given (PRIVMSG)", hostname, getnick(peer) ), _); REPLY(412, WRITE( ":%s 412 %s :No text to send", hostname, getnick(peer) ), _); REPLY(421, WRITE( ":%s 421 %s %s :Unknown command", hostname, getnick(peer), command ), command, _); REPLY(431, WRITE( ":%s 431 %s :No nickname given", hostname, getnick(peer) ), _); REPLY(442, WRITE( ":%s 442 %s %s :You're not on that channel", hostname, getnick(peer), channel ), channel, _); REPLY(451, WRITE( ":%s 451 %s :You have not registered", hostname, getnick(peer) ), _); REPLY(461, WRITE( ":%s 461 %s %s :Not enough parameters", hostname, getnick(peer), command ), command, _); REPLY(462, WRITE( ":%s 462 %s :Unauthorized command (already registered)", hostname, getnick(peer) ), _); REPLY(471, WRITE( ":%s 471 %s %s :Cannot join channel (+l)", hostname, getnick(peer), channel ), channel, _); default: warn("unknown reply: %d", number); WRITE( ":%s 421 %s err :Reply %d is not implemented yet", hostname, getnick(peer), number ); } } int reply(const struct Peer *peer, int number, ...) { va_list args; int ret; va_start(args, number); ret = vreply(peer, number, args); va_end(args); return ret; }