Mercurial > irccd
changeset 956:5e682f1cebcc
irccd: improve SSL support and add basic whois
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 21 Jan 2021 09:49:42 +0100 |
parents | 9b167c5c4b78 |
children | 3167c51f0c84 |
files | CMakeLists.txt extern/libcompat/CMakeLists.txt extern/libcompat/src/compat.h.in extern/libcompat/src/strtok_r.c irccdctl/main.c lib/irccd/channel.h lib/irccd/event.c lib/irccd/event.h lib/irccd/js-plugin.c lib/irccd/jsapi-server.c lib/irccd/limits.h lib/irccd/server.c lib/irccd/server.h |
diffstat | 13 files changed, 462 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Wed Jan 20 17:01:51 2021 +0100 +++ b/CMakeLists.txt Thu Jan 21 09:49:42 2021 +0100 @@ -32,7 +32,7 @@ option(IRCCD_WITH_TESTS "Enable unit tests" Off) if (CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") - set(CMAKE_C_FLAGS "-Wall -Wextra") + set(CMAKE_C_FLAGS "-Wall -Wextra ${CMAKE_C_FLAGS}") endif () include(GNUInstallDirs)
--- a/extern/libcompat/CMakeLists.txt Wed Jan 20 17:01:51 2021 +0100 +++ b/extern/libcompat/CMakeLists.txt Thu Jan 21 09:49:42 2021 +0100 @@ -60,6 +60,7 @@ strdup strndup strnlen + strtok_r ) set(
--- a/extern/libcompat/src/compat.h.in Wed Jan 20 17:01:51 2021 +0100 +++ b/extern/libcompat/src/compat.h.in Thu Jan 21 09:49:42 2021 +0100 @@ -16,6 +16,7 @@ #cmakedefine COMPAT_HAVE_STRNDUP #cmakedefine COMPAT_HAVE_STRNLEN #cmakedefine COMPAT_HAVE_STRSEP +#cmakedefine COMPAT_HAVE_STRTOK_R #cmakedefine COMPAT_HAVE_VERR #cmakedefine COMPAT_HAVE_VERRC #cmakedefine COMPAT_HAVE_VERRX @@ -169,4 +170,9 @@ strsep(char **, const char *); #endif +#ifndef COMPAT_HAVE_STRTOK_R +char * +strtok_r(char *, const char *, char **); +#endif + #endif /* !LIBCOMPAT_COMPAT_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extern/libcompat/src/strtok_r.c Thu Jan 21 09:49:42 2021 +0100 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +char * +strtok_r(char *s, const char *delim, char **last) +{ + const char *spanp; + int c, sc; + char *tok; + + if (s == NULL && (s = *last) == NULL) + return (NULL); + + /* + * Skip (span) leading delimiters (s += strspn(s, delim), sort of). + */ +cont: + c = *s++; + for (spanp = delim; (sc = *spanp++) != 0;) { + if (c == sc) + goto cont; + } + + if (c == 0) { /* no non-delimiter characters */ + *last = NULL; + return (NULL); + } + tok = s - 1; + + /* + * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). + * Note that delim must have one NUL; we stop if we see that, too. + */ + for (;;) { + c = *s++; + spanp = delim; + do { + if ((sc = *spanp++) == c) { + if (c == 0) + s = NULL; + else + s[-1] = '\0'; + *last = s; + return (tok); + } + } while (sc != 0); + } + /* NOTREACHED */ +}
--- a/irccdctl/main.c Wed Jan 20 17:01:51 2021 +0100 +++ b/irccdctl/main.c Thu Jan 21 09:49:42 2021 +0100 @@ -51,9 +51,10 @@ while (!(nl = strstr(in, "\n"))) { char buf[IRC_BUF_MAX] = {0}; + ssize_t nr; - if (recv(sock, buf, sizeof (buf) - 1, 0) <= 0) - err(1, "abort"); + if ((nr = recv(sock, buf, sizeof (buf) - 1, 0)) <= 0) + errc(1, nr == 0 ? ECONNRESET : errno, "abort"); if (strlcat(in, buf, sizeof (in)) >= sizeof (in)) errc(1, EMSGSIZE, "abort"); } @@ -236,16 +237,80 @@ } static void +show_connect(char *line) +{ + const char *args[2] = {0}; + + if (irc_util_split(line, args, 2) == 2) { + printf("event: onConnect\n"); + printf("server: %s\n", args[0]); + } +} + +static void +show_disconnect(char *line) +{ + const char *args[2] = {0}; + + if (irc_util_split(line, args, 2) == 2) { + printf("event: onDisonnect\n"); + printf("server: %s\n", args[0]); + } +} + +static void show_invite(char *line) { const char *args[5] = {0}; if (irc_util_split(line, args, 5) == 5) { printf("event: onInvite\n"); - printf("server: %s", args[1]); - printf("origin: %s", args[2]); - printf("channel: %s", args[3]); - printf("nickname: %s", args[4]); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + printf("nickname: %s\n", args[4]); + } +} + +static void +show_join(char *line) +{ + const char *args[4] = {0}; + + if (irc_util_split(line, args, 4) == 4) { + printf("event: onJoin\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + } +} + +static void +show_kick(char *line) +{ + const char *args[6] = {0}; + + if (irc_util_split(line, args, 6) >= 5) { + printf("event: onKick\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + printf("target: %s\n", args[4]); + printf("reason: %s\n", args[5] ? args[5] : ""); + } +} + +static void +show_me(char *line) +{ + const char *args[5] = {0}; + + if (irc_util_split(line, args, 5) == 5) { + printf("event: onMe\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + printf("message: %s\n", args[4]); } } @@ -263,12 +328,114 @@ } } +static void +show_mode(char *line) +{ + const char *args[8] = {0}; + + if (irc_util_split(line, args, 8) >= 5) { + printf("event: onMode\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + printf("mode: %s\n", args[4]); + printf("limit: %s\n", (args[5] ? args[5] : "")); + printf("user: %s\n", (args[6] ? args[6] : "")); + printf("mask: %s\n", (args[7] ? args[7] : "")); + } +} + +static void +show_nick(char *line) +{ + const char *args[4] = {0}; + + if (irc_util_split(line, args, 4) == 4) { + printf("event: onNick\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("nickname: %s\n", args[3]); + } +} + +static void +show_notice(char *line) +{ + const char *args[5] = {0}; + + if (irc_util_split(line, args, 5) == 5) { + printf("event: onNotice\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + printf("message: %s\n", args[4]); + } +} + +static void +show_part(char *line) +{ + const char *args[5] = {0}; + + if (irc_util_split(line, args, 5) >= 4) { + printf("event: onPart\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + printf("reason: %s\n", (args[4] ? args[4] : "")); + } +} + +static void +show_topic(char *line) +{ + const char *args[5] = {0}; + + if (irc_util_split(line, args, 5) >= 4) { + printf("event: onTopic\n"); + printf("server: %s\n", args[1]); + printf("origin: %s\n", args[2]); + printf("channel: %s\n", args[3]); + printf("topic: %s\n", args[4]); + } +} + +static void +show_whois(char *line) +{ + const char *args[6] = {0}; + char *p, *token; + + if (irc_util_split(line, args, 6) >= 4) { + printf("event: onWhois\n"); + printf("server: %s\n", args[1]); + printf("nickname: %s\n", args[2]); + printf("username: %s\n", args[3]); + printf("hostname: %s\n", args[4]); + printf("username: %s\n", args[5]); + printf("channels: "); + + + } +} + static const struct { const char *event; void (*show)(char *); } watchtable[] = { - { "EVENT-INVITE", show_invite }, - { "EVENT-MESSAGE", show_message } + { "EVENT-CONNECT", show_connect }, + { "EVENT-DISCONNECT", show_disconnect }, + { "EVENT-INVITE", show_invite }, + { "EVENT-JOIN", show_join }, + { "EVENT-KICK", show_kick }, + { "EVENT-MESSAGE", show_message }, + { "EVENT-ME", show_me }, + { "EVENT-MODE", show_mode }, + { "EVENT-NICK", show_nick }, + { "EVENT-NOTICE", show_notice }, + { "EVENT-PART", show_part }, + { "EVENT-TOPIC", show_topic }, + { "EVENT-WHOIS", show_whois } }; static void @@ -277,6 +444,7 @@ for (size_t i = 0; i < IRC_UTIL_SIZE(watchtable); ++i) { if (strncmp(watchtable[i].event, ev, strlen(watchtable[i].event)) == 0) { watchtable[i].show(ev); + printf("\n"); break; } }
--- a/lib/irccd/channel.h Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/channel.h Thu Jan 21 09:49:42 2021 +0100 @@ -24,9 +24,6 @@ #include "limits.h" -#define IRC_CHANNEL_NAME_MAX 128 -#define IRC_CHANNEL_PASSWORD_MAX 128 - struct irc_channel_user { char nickname[IRC_NICKNAME_MAX]; char mode;
--- a/lib/irccd/event.c Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/event.c Thu Jan 21 09:49:42 2021 +0100 @@ -113,6 +113,12 @@ int written = 0; switch (ev->type) { + case IRC_EVENT_CONNECT: + written = snprintf(str, strsz, "EVENT-CONNECT %s", ev->server->name); + break; + case IRC_EVENT_DISCONNECT: + written = snprintf(str, strsz, "EVENT-DISCONNECT %s", ev->server->name); + break; case IRC_EVENT_INVITE: written = snprintf(str, strsz, "EVENT-INVITE %s %s %s %s", ev->server->name, ev->msg.prefix, ev->msg.args[0], ev->msg.args[1]); @@ -123,7 +129,8 @@ break; case IRC_EVENT_KICK: written = snprintf(str, strsz, "EVENT-KICK %s %s %s %s %s", ev->server->name, - ev->msg.prefix, ev->msg.args[0], ev->msg.args[1], ev->msg.args[2]); + ev->msg.prefix, ev->msg.args[0], ev->msg.args[1], + ev->msg.args[2] ? ev->msg.args[2] : ""); break; case IRC_EVENT_ME: written = snprintf(str, strsz, "EVENT-ME %s %s %s %s", ev->server->name, @@ -134,9 +141,12 @@ ev->msg.prefix, ev->msg.args[0], ev->msg.args[1]); break; case IRC_EVENT_MODE: - written = snprintf(str, strsz, "EVENT-MODE %s %s %s %s %s %s %s", ev->server->name, - ev->msg.prefix, ev->msg.args[0], ev->msg.args[1], ev->msg.args[2], - ev->msg.args[3], ev->msg.args[4]); + written = snprintf(str, strsz, "EVENT-MODE %s %s %s %s %s %s %s", + ev->server->name, ev->msg.prefix, ev->msg.args[0], + ev->msg.args[1] ? ev->msg.args[1] : "", + ev->msg.args[2] ? ev->msg.args[2] : "", + ev->msg.args[3] ? ev->msg.args[3] : "", + ev->msg.args[4] ? ev->msg.args[4] : ""); break; case IRC_EVENT_NICK: written = snprintf(str, strsz, "EVENT-NICK %s %s %s", ev->server->name, @@ -148,15 +158,38 @@ break; case IRC_EVENT_PART: written = snprintf(str, strsz, "EVENT-PART %s %s %s %s", ev->server->name, - ev->msg.prefix, ev->msg.args[0], ev->msg.args[1]); + ev->msg.prefix, ev->msg.args[0], + ev->msg.args[1] ? ev->msg.args[1] : ""); break; case IRC_EVENT_TOPIC: written = snprintf(str, strsz, "EVENT-TOPIC %s %s %s %s", ev->server->name, ev->msg.prefix, ev->msg.args[0], ev->msg.args[1]); break; + case IRC_EVENT_WHOIS: + snprintf(str, strsz, "EVENT-WHOIS %s %s %s %s %s ", + ev->server->name, ev->whois->nickname, ev->whois->username, + ev->whois->realname, ev->whois->hostname); + + for (size_t i = 0; i < ev->whois->channelsz; ++i) { + size_t s; + + /* Concat channel and their modes. */ + strlcat(str, (char []) {ev->whois->channels[i].mode, '\0' }, strsz); + strlcat(str, ev->whois->channels[i].channel, strsz); + + if ((s = strlcat(str, " ", strsz)) >= strsz) + goto emsgsize; + + written = s; + } + break; default: break; } return written > 0; + +emsgsize: + errno = EMSGSIZE; + return false; }
--- a/lib/irccd/event.h Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/event.h Thu Jan 21 09:49:42 2021 +0100 @@ -55,7 +55,10 @@ struct irc_event { enum irc_event_type type; struct irc_server *server; - struct irc_event_msg msg; + union { + struct irc_event_msg msg; + struct irc_server_whois *whois; + }; }; bool
--- a/lib/irccd/js-plugin.c Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/js-plugin.c Thu Jan 21 09:49:42 2021 +0100 @@ -97,6 +97,31 @@ } } +static void +push_whois(duk_context *ctx, const struct irc_event *ev) +{ + duk_push_object(ctx); + duk_push_string(ctx, ev->whois->nickname); + duk_put_prop_string(ctx, -2, "nickname"); + duk_push_string(ctx, ev->whois->username); + duk_put_prop_string(ctx, -2, "username"); + duk_push_string(ctx, ev->whois->realname); + duk_put_prop_string(ctx, -2, "realname"); + duk_push_string(ctx, ev->whois->hostname); + duk_put_prop_string(ctx, -2, "hostname"); + duk_push_array(ctx); + for (size_t i = 0; i < ev->whois->channelsz; ++i) { + printf("[%s] = [%c]\n", ev->whois->channels[i].channel, ev->whois->channels[i].mode); + duk_push_object(ctx); + duk_push_string(ctx, ev->whois->channels[i].channel); + duk_put_prop_string(ctx, -2, "channel"); + duk_push_sprintf(ctx, "%c", ev->whois->channels[i].mode); + duk_put_prop_string(ctx, -2, "mode"); + duk_put_prop_index(ctx, -2, i); + } + duk_put_prop_string(ctx, -2, "channels"); +} + static const char ** get_table(duk_context *ctx, const char *name, char ***ptable) { @@ -315,7 +340,7 @@ break; case IRC_EVENT_NAMES: call(plg, "onNames", "Ss x", ev->server, ev->msg.args[1], - push_names); + push_names, ev); break; case IRC_EVENT_NICK: call(plg, "onNick", "Ss s", ev->server, ev->msg.prefix, @@ -334,6 +359,7 @@ ev->msg.args[0], ev->msg.args[1]); break; case IRC_EVENT_WHOIS: + call(plg, "onWhois", "Sx", ev->server, push_whois, ev); break; default: break;
--- a/lib/irccd/jsapi-server.c Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/jsapi-server.c Thu Jan 21 09:49:42 2021 +0100 @@ -415,15 +415,15 @@ static duk_ret_t Server_prototype_whois(duk_context *ctx) { - (void)ctx; + struct irc_server *s = self(ctx); + const char *target = duk_require_string(ctx, 0); + #if 0 if (target.empty()) throw server_error(server_error::invalid_nickname); #endif -#if 0 duk_push_boolean(ctx, irc_server_whois(s, target)); -#endif return 1; }
--- a/lib/irccd/limits.h Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/limits.h Thu Jan 21 09:49:42 2021 +0100 @@ -19,7 +19,10 @@ #ifndef IRCCD_LIMITS_H #define IRCCD_LIMITS_H -/* IRC limits. */ +/* + * Those were IRC limits but not strictly following RFC 1459 because lots of + * servers allow higher limits. + */ #define IRC_NICKNAME_MAX 32 #define IRC_USERNAME_MAX 32 #define IRC_REALNAME_MAX 64 @@ -29,11 +32,11 @@ #define IRC_USERMODES_MAX 16 #define IRC_MESSAGE_MAX 512 -#define IRC_ARGS_MAX 16 +#define IRC_ARGS_MAX 32 /* Network limits. */ #define IRC_HOST_MAX 32 -#define IRC_BUF_MAX 8192 +#define IRC_BUF_MAX 128000 /* Types limits. */ #define IRC_NAME_MAX 16
--- a/lib/irccd/server.c Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/server.c Thu Jan 21 09:49:42 2021 +0100 @@ -303,6 +303,56 @@ ev->type = IRC_EVENT_NAMES; } +static void +handle_whoisuser(struct irc_server *s, struct irc_event *ev) +{ + (void)ev; + + strlcpy(s->whois.nickname, ev->msg.args[1], sizeof (s->whois.nickname)); + strlcpy(s->whois.username, ev->msg.args[2], sizeof (s->whois.username)); + strlcpy(s->whois.hostname, ev->msg.args[3], sizeof (s->whois.hostname)); + strlcpy(s->whois.realname, ev->msg.args[5], sizeof (s->whois.realname)); +} + +static void +add_whois_channel(struct irc_server *s, const char *channel) +{ + char mode = 0; + + s->whois.channels = irc_util_reallocarray(s->whois.channels, + ++s->whois.channelsz, sizeof (*s->whois.channels)); + + /* TODO: split this to refactor add_nick. */ + for (size_t i = 0; i < IRC_UTIL_SIZE(s->prefixes); ++i) { + if (channel[0] == s->prefixes[i].token) { + mode = s->prefixes[i].mode; + ++channel; + break; + } + } + + s->whois.channels[s->whois.channelsz - 1].mode = mode; + strlcpy(s->whois.channels[s->whois.channelsz - 1].channel, channel, + sizeof (s->whois.channels[0].channel)); +} + +static void +handle_whoischannels(struct irc_server *s, struct irc_event *ev) +{ + char *p, *token; + + for (p = ev->msg.args[2]; (token = strtok_r(p, " ", &p)); ) + if (strlen(token) > 0) + add_whois_channel(s, token); +} + +static void +handle_endofwhois(struct irc_server *s, struct irc_event *ev) +{ + ev->type = IRC_EVENT_WHOIS; + ev->whois = &s->whois; +} + static const struct handler { const char *command; void (*handle)(struct irc_server *, struct irc_event *); @@ -310,6 +360,9 @@ /* Must be kept ordered. */ { "001", handle_connect }, { "005", handle_support }, + { "311", handle_whoisuser }, + { "318", handle_endofwhois }, + { "319", handle_whoischannels }, { "353", handle_names }, { "366", handle_endofnames }, { "INVITE", handle_invite }, @@ -419,9 +472,11 @@ switch ((r = SSL_get_error(s->ssl, ret))) { case SSL_ERROR_WANT_READ: + printf("new ssl state: %d\n", s->ssl_state); s->ssl_state = IRC_SERVER_SSL_NEED_READ; break; case SSL_ERROR_WANT_WRITE: + printf("new ssl state: %d\n", s->ssl_state); s->ssl_state = IRC_SERVER_SSL_NEED_WRITE; break; case SSL_ERROR_SSL: @@ -465,8 +520,6 @@ handshake(s); else { #if defined(IRCCD_WITH_SSL) - int r; - if (!s->ctx) s->ctx = SSL_CTX_new(TLS_method()); if (!s->ssl) { @@ -474,10 +527,8 @@ SSL_set_fd(s->ssl, s->fd); } - if ((r = SSL_connect(s->ssl)) > 0) - handshake(s); - - update(s, r); + SSL_set_connect_state(s->ssl); + handshake(s); #endif } } @@ -543,28 +594,50 @@ } } +static size_t +input_ssl(struct irc_server *s, char *dst, size_t dstsz) +{ + int nr; + + if ((nr = SSL_read(s->ssl, dst, dstsz)) <= 0) { + update(s, nr); + return 0; + } + + s->ssl_state = IRC_SERVER_SSL_NONE; + + return nr; +} + +static size_t +input_clear(struct irc_server *s, char *buf, size_t bufsz) +{ + ssize_t nr; + + if ((nr = recv(s->fd, buf, bufsz, 0)) <= 0) { + clear(s); + return 0; + } + + return nr; +} + static void input(struct irc_server *s) { - char buf[IRC_MESSAGE_MAX] = {0}; - ssize_t nr = 0; + size_t len = strlen(s->in); + size_t cap = sizeof (s->in) - len - 1; + size_t nr = 0; if (s->flags & IRC_SERVER_FLAGS_SSL) { #if defined(IRCCD_WITH_SSL) - nr = SSL_read(s->ssl, buf, sizeof (buf) - 1); - update(s, nr); + nr = input_ssl(s, s->in + len, cap); #endif - } else { - if ((nr = recv(s->fd, buf, sizeof (buf) - 1, 0)) < 0) - clear(s); - } + } else + nr = input_clear(s, s->in + len, cap); - if (nr > 0) { - if (strlcat(s->in, buf, sizeof (s->in)) >= sizeof (s->in)) { - irc_log_warn("server %s: input buffer too long", s->name); - clear(s); - } - } + if (nr > 0) + s->in[len + nr] = '\0'; } static void @@ -949,6 +1022,19 @@ return irc_server_send(s, "NOTICE %s: %s", channel, message); } +bool +irc_server_whois(struct irc_server *s, const char *target) +{ + assert(s); + assert(target); + + /* Cleanup previous result. */ + free(s->whois.channels); + memset(&s->whois, 0, sizeof (s->whois)); + + return irc_server_send(s, "WHOIS %s", target); +} + void irc_server_incref(struct irc_server *s) { @@ -965,6 +1051,7 @@ if (--s->refc == 0) { clear(s); + free(s->whois.channels); free(s->channels); free(s); }
--- a/lib/irccd/server.h Wed Jan 20 17:01:51 2021 +0100 +++ b/lib/irccd/server.h Thu Jan 21 09:49:42 2021 +0100 @@ -67,6 +67,18 @@ #endif +struct irc_server_whois { + char nickname[IRC_NICKNAME_MAX]; + char username[IRC_USERNAME_MAX]; + char realname[IRC_REALNAME_MAX]; + char hostname[IRC_HOST_MAX]; + struct { + char channel[IRC_CHANNEL_MAX]; + char mode; + } *channels; + size_t channelsz; +}; + struct irc_server { /* Connection settings. */ char name[IRC_NAME_MAX]; @@ -103,6 +115,9 @@ enum irc_server_ssl_state ssl_state; #endif + /* Whois being stored. */ + struct irc_server_whois whois; + /* Reference count. */ size_t refc; struct irc_server *next; @@ -172,6 +187,9 @@ bool irc_server_notice(struct irc_server *, const char *, const char *); +bool +irc_server_whois(struct irc_server *, const char *); + void irc_server_incref(struct irc_server *);