Index: kefile
===================================================================
--- Makefile	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,18 +1,0 @@
-PREFIX?=	/usr/local
-BINDIR=		${PREFIX}/sbin
-MANDIR=		${PREFIX}/man/man8
-
-PROG=		icbd
-SRCS=		cmd.c dns.c icb.c icbd.c logger.c
-MAN=		icbd.8
-
-.ifdef __OpenBSD__
-CFLAGS+=	-W -Wall -Werror
-CFLAGS+=	-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations
-CFLAGS+=	-Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare
-.endif
-
-DPADD=		${LIBEVENT}
-LDADD=		-levent
-
-.include <bsd.prog.mk>
Index: README
===================================================================
--- README	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ README	(revision b47ffaa8415a583287cc37c2b1616450f1ac57b2)
@@ -1,38 +1,21 @@
- _____________________
-( A simple ICB daemon )
- ---------------------
-            \
-             \
-              \                 ,__--**@@@**--__,
-               \             ,@%*               *%@m,
-                          ,@*  #    +@*#          @ *@,
-                        ,@*    @       # __       @    @,
-                    ,*@m#,     @,     m*@  %_-   ,@     ,#m@*,
-              ,@@*-%     @      #                #      @     %-+m,
-             @     @     @#=====#================#=====#@     @    %,
-            @*     ,*@m,##                              ##,m@*,     @
-            #    :@     #====---__________________---====#     @:   @
-           @*    :@     @                                @.    @:   @
-           @      *m__m*         #m,         .#           *m__*     @
-           @      @       .#    %  @         @ @            =-     @*
-           *,     %      ,% @   @   @       @. *%    #,     .-    ,@
-            @     *@     @   @, @   *@    :@    @  ,@ *,    @.    @
-            @      @@.  %      *#     @ ,@*     #+*    %   .@     @
-            @     %  @, @ m--#@+*+@#-- # --#@+*+@#--m  @  ,@+     @
-           .@     @   *@# | @  @    @     @  @    @ | +@ ,@ %     *,
-          ,@      @,     @  @*^     @     @*^     @  @ #%*  @      %,
-         ,@       *%     @   @     @       %     @   @      @        %
-         @       ,*@      %   *=_=*         *=_=*   %      ,*+        @
-        %*     m*  @      %                         %      %  @,       @
-        @     @*   %     ,@                         @,     @   @       @:
-        @     @    @     @            *_*            @      @   @      @:
-        @:    %,   %,    @**__,                 ,__**@      @  _%      @
-         @,    *_   @,   @  @. *--__,     ,__--* .@  @     @  #,     ,@*
-           *--__+#    @,  @  @,    . ^^^^^ .    ,@   *   ,@     *+@@*
-                        ^*+#  *%__*%,m***m,%*__%*   #@@+*
-                                    O     O  *=
-                                     *m_m*
-                                       # #
-                                        # @*#
-                                         #  -#
-                                          #+*^
+icbd: a simple yet secure ICB daemon written in C
+=================================================
+
+FAQ:
+====
+
+Q. WTF?
+A. http://www.icb.net/
+
+Q. Ahoi! Where are the protocol specs?
+A. http://www.icb.net/_jrudd/icb/protocol.html
+
+Q. This' really old shit, man!
+A. Yes, it is!
+
+Q. Why do you need that shit, man?
+A. Well, I don't need it at all!
+
+Q. Any clients?
+A. There are icb, ircII, irssi (with icb plugin), zenicb (emacs plugin) and
+   an irc to icb proxy - icbirc.
Index: d.c
===================================================================
--- cmd.c	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,424 +1,0 @@
-/*
- * Copyright (c) 2009, 2010, 2013 Mike Belopuhov
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <netdb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <vis.h>
-#include <event.h>
-
-#include "icb.h"
-#include "icbd.h"
-
-extern int creategroups;
-
-void icb_cmd_help(struct icb_session *, char *);
-void icb_cmd_beep(struct icb_session *, char *);
-void icb_cmd_boot(struct icb_session *, char *);
-void icb_cmd_change(struct icb_session *, char *);
-void icb_cmd_name(struct icb_session *, char *);
-void icb_cmd_nobeep(struct icb_session *, char *);
-void icb_cmd_personal(struct icb_session *, char *);
-void icb_cmd_pass(struct icb_session *, char *);
-void icb_cmd_topic(struct icb_session *, char *);
-void icb_cmd_who(struct icb_session *, char *);
-
-void *
-icb_cmd_lookup(char *cmd)
-{
-	struct {
-		const char	*cmd;
-		void		(*handler)(struct icb_session *, char *);
-	} cmdtab[] = {
-		{ "?",		icb_cmd_help },
-		{ "beep",	icb_cmd_beep },
-		{ "boot",	icb_cmd_boot },
-		{ "g",		icb_cmd_change },
-		{ "m",		icb_cmd_personal },
-		{ "msg",	icb_cmd_personal },
-		{ "name",	icb_cmd_name },
-		{ "nobeep",	icb_cmd_nobeep },
-		{ "pass",	icb_cmd_pass },
-		{ "topic",	icb_cmd_topic },
-		{ "w",		icb_cmd_who },
-		{ NULL,		NULL }
-	};
-	int i;
-
-	for (i = 0; cmdtab[i].cmd != NULL; i++)
-		if (strcasecmp(cmdtab[i].cmd, cmd) == 0)
-			return (cmdtab[i].handler);
-	return (NULL);
-}
-
-void
-icb_cmd_help(struct icb_session *is, char *arg __attribute__((unused)))
-{
-	icb_status(is, STATUS_HELP, "Server supports following commands:");
-	icb_status(is, STATUS_HELP, "beep boot g m name nobeep pass topic w");
-}
-
-void
-icb_cmd_beep(struct icb_session *is, char *arg)
-{
-	struct icb_group *ig = is->group;
-	struct icb_session *s;
-	char whom[ICB_MAXNICKLEN];
-
-	if (strlen(arg) == 0) {
-		icb_error(is, "Invalid user");
-		return;
-	}
-
-	icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
-
-	/* Search in the same group first */
-	LIST_FOREACH(s, &ig->sess, entry) {
-		if (strcmp(s->nick, whom) == 0)
-			break;
-	}
-	if (s == NULL) {
-		/* See if we can find someone else to beep */
-		LIST_FOREACH(ig, &groups, entry) {
-			if (strcmp(is->group->name, ig->name) == 0)
-				continue;
-			LIST_FOREACH(s, &ig->sess, entry) {
-				if (strcmp(s->nick, whom) == 0)
-					break;
-			}
-			if (s != NULL)
-				break;
-		}
-	}
-	if (s == NULL) {
-		icb_status(is, STATUS_NOTIFY, "%s is not signed on", whom);
-		return;
-	}
-	if (s == is) {
-		icb_error(is, "Very funny... Not!");
-		return;
-	}
-
-	if (ISSETF(s->flags, ICB_SF_NOBEEP | ICB_SF_NOBEEP2)) {
-		icb_error(is, "User has nobeep enabled");
-		if (ISSETF(s->flags, ICB_SF_NOBEEP2))
-			icb_status(s, STATUS_NOBEEP,
-			    "%s attempted to beep you", is->nick);
-		return;
-	}
-
-	icb_sendfmt(s, "%c%s", ICB_M_BEEP, is->nick);
-}
-
-void
-icb_cmd_boot(struct icb_session *is, char *arg)
-{
-	struct icb_group *ig;
-	struct icb_session *s;
-	char whom[ICB_MAXNICKLEN];
-
-	/* to boot or not to boot, that is the question */
-	ig = is->group;
-	if (!icb_ismod(ig, is)) {
-		icb_status(is, STATUS_NOTIFY, "Sorry, booting is a privilege "
-		    "you don't possess");
-		return;
-	}
-
-	if (strlen(arg) == 0) {
-		icb_error(is, "Invalid user");
-		return;
-	}
-
-	icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
-
-	/* who would be a target then? */
-	LIST_FOREACH(s, &ig->sess, entry) {
-		if (strcmp(s->nick, whom) == 0)
-			break;
-	}
-	if (s == NULL) {
-		icb_status(is, STATUS_NOTIFY, "No such user");
-		return;
-	}
-	if (s == is) {
-		icb_error(is, "Just quit, would you?");
-		return;
-	}
-
-	/* okay, here we go, but first, be polite and notify a user */
-	icb_status(s, STATUS_BOOT, "%s booted you", is->nick);
-	icb_status_group(s->group, s, STATUS_BOOT, "%s was booted", s->nick);
-	icbd_drop(s, "booted");
-}
-
-void
-icb_cmd_change(struct icb_session *is, char *arg)
-{
-	struct icb_group *ig;
-	struct icb_session *s;
-	char group[ICB_MAXGRPLEN];
-	int changing = 0;
-
-	if (strlen(arg) == 0) {
-		icb_error(is, "Invalid group name");
-		return;
-	}
-
-	icb_vis(group, arg, ICB_MAXGRPLEN, VIS_SP);
-
-	LIST_FOREACH(ig, &groups, entry) {
-		if (strcmp(ig->name, group) == 0)
-			break;
-	}
-	if (ig == NULL) {
-		if (!creategroups) {
-			icb_error(is, "Can't create new groups");
-			return;
-		} else {
-			if ((ig = icb_addgroup(is, group)) == NULL) {
-				icb_error(is, "Can't create group %s", group);
-				return;
-			}
-			icbd_log(NULL, LOG_DEBUG, "%s created group %s",
-			    is->nick, group);
-		}
-	}
-
-	/* see if we're changing to the same group */
-	if (is->group && is->group == ig) {
-		icb_error(is, "You are already in that group");
-		return;
-	}
-
-	LIST_FOREACH(s, &ig->sess, entry) {
-		if (strcmp(s->nick, is->nick) == 0) {
-			icb_error(is, "Nick is already in use");
-			return;
-		}
-	}
-
-	if (is->group) {
-		changing = 1;
-		if (icb_ismod(is->group, is))
-			(void)icb_pass(is->group, is, NULL);
-		LIST_REMOVE(is, entry);
-		icb_status_group(is->group, NULL, STATUS_DEPART,
-		    "%s (%s@%s) just left", is->nick, is->client, is->host);
-	}
-
-	is->group = ig;
-	LIST_INSERT_HEAD(&ig->sess, is, entry);
-
-	/* notify group */
-	icb_status_group(ig, is, changing ? STATUS_ARRIVE : STATUS_SIGNON,
-	    "%s (%s@%s) entered group", is->nick, is->client, is->host);
-
-	/* acknowledge successful join */
-	icb_status(is, STATUS_STATUS, "You are now in group %s%s", ig->name,
-	    icb_ismod(ig, is) ? " as moderator" : "");
-
-	/* send user a topic name */
-	if (strlen(ig->topic) > 0)
-		icb_status(is, STATUS_TOPIC, "The topic is: %s", ig->topic);
-}
-
-void
-icb_cmd_name(struct icb_session *is, char *arg)
-{
-	struct icb_group *ig = is->group;
-	struct icb_session *s;
-	char nick[ICB_MAXNICKLEN];
-
-	if (strlen(arg) == 0) {
-		icb_status(is, STATUS_NAME, "Your nickname is %s",
-		    is->nick);
-		return;
-	}
-	if (strcasecmp(arg, "admin") == 0) {
-		icb_error(is, "Wuff wuff!");
-		return;
-	}
-	/* sanitize user input */
-	if (strlen(arg) > ICB_MAXNICKLEN)
-		arg[ICB_MAXNICKLEN - 1] = '\0';
-	icb_vis(nick, arg, ICB_MAXNICKLEN, VIS_SP);
-	LIST_FOREACH(s, &ig->sess, entry) {
-		if (strcmp(s->nick, nick) == 0) {
-			icb_error(is, "Nick is already in use");
-			return;
-		}
-	}
-	icb_status_group(ig, NULL, STATUS_NAME,
-	    "%s changed nickname to %s", is->nick, nick);
-	strlcpy(is->nick, nick, sizeof is->nick);
-}
-
-void
-icb_cmd_nobeep(struct icb_session *is, char *arg)
-{
-	if (strlen(arg) == 0) {
-		/* fail if we have verbose turned on */
-		if (ISSETF(is->flags, ICB_SF_NOBEEP2)) {
-			icb_error(is, "Can't toggle your nobeep status");
-			return;
-		}
-		/* otherwise toggle the status */
-		if (ISSETF(is->flags, ICB_SF_NOBEEP))
-			CLRF(is->flags, ICB_SF_NOBEEP);
-		else
-			SETF(is->flags, ICB_SF_NOBEEP);
-		icb_status(is, STATUS_NOBEEP, "No-Beep %s",
-		    ISSETF(is->flags, ICB_SF_NOBEEP) ? "on" : "off");
-		return;
-	}
-
-	if (strcmp(arg, "on") == 0) {
-		SETF(is->flags, ICB_SF_NOBEEP);
-		CLRF(is->flags, ICB_SF_NOBEEP2); /* can't be on and verbose */
-		icb_status(is, STATUS_NOBEEP, "No-Beep on");
-	} else if (strcmp(arg, "verbose") == 0) {
-		SETF(is->flags, ICB_SF_NOBEEP2);
-		CLRF(is->flags, ICB_SF_NOBEEP); /* can't be on and verbose */
-		icb_status(is, STATUS_NOBEEP, "No-Beep on (verbose)");
-	} else if (strcmp(arg, "off") == 0) {
-		CLRF(is->flags, ICB_SF_NOBEEP | ICB_SF_NOBEEP2);
-		icb_status(is, STATUS_NOBEEP, "No-Beep off");
-	} else
-		icb_error(is, "Invalid nobeep mode");
-}
-
-void
-icb_cmd_personal(struct icb_session *is, char *arg)
-{
-	char *p;
-
-	if ((p = strchr(arg, ' ')) == 0) {
-		icb_error(is, "Empty message");
-		return;
-	}
-	*p = '\0';
-	icb_privmsg(is, arg, ++p);
-}
-
-void
-icb_cmd_pass(struct icb_session *is, char *arg)
-{
-	struct icb_group *ig = is->group;
-	struct icb_session *s;
-	char whom[ICB_MAXNICKLEN];
-
-	if (icb_ismod(ig, is)) {
-		/*
-		 * we're a current group moderator, allow to relinquish
-		 * the right and to pass it down to everybody else.
-		 */
-		if (strlen(arg) == 0) {
-			/* no argument: relinquish moderator */
-			(void)icb_pass(ig, ig->mod, NULL);
-			return;
-		}
-		icb_vis(whom, arg, ICB_MAXNICKLEN, VIS_SP);
-		LIST_FOREACH(s, &ig->sess, entry) {
-			if (strcmp(s->nick, whom) == 0)
-				break;
-		}
-		if (s == NULL) {
-			icb_status(is, STATUS_NOTIFY, "No such user");
-			return;
-		}
-		if (icb_pass(ig, ig->mod, s) < 0)
-			icb_error(is, "Failed to pass group moderation.");
-	} else {
-		/*
-		 * if group is moderated and we're not the moderator,
-		 * but modtab is enabled, then check the permission
-		 * and pass moderation if successful.  if there's no
-		 * current moderator, don't enforce the modtab.
-		 */
-		if (!icb_modpermit(is, ig->mod ? 1 : 0)) {
-			icb_error(is, "Operation not permitted.");
-			return;
-		}
-		if (icb_pass(ig, ig->mod, is) < 0)
-			icb_error(is, "Failed to acquire group moderation.");
-	}
-}
-
-void
-icb_cmd_topic(struct icb_session *is, char *arg)
-{
-	struct icb_group *ig = is->group;
-	char topic[ICB_MAXTOPICLEN];
-
-	if (strlen(arg) == 0) {	/* querying the topic */
-		if (strlen(ig->topic) > 0)
-			icb_status(is, STATUS_TOPIC, "The topic is: %s",
-			    ig->topic);
-		else
-			icb_status(is, STATUS_TOPIC, "The topic is not set.");
-	} else {		/* setting the topic */
-		if (!icb_ismod(ig, is)) {
-			icb_status(is, STATUS_NOTIFY, "Setting the topic is "
-			    "only for moderators.");
-			return;
-		}
-		icb_vis(topic, arg, ICB_MAXTOPICLEN, 0);
-		strlcpy(ig->topic, topic, sizeof ig->topic);
-		icb_status_group(ig, NULL, STATUS_TOPIC,
-		    "%s changed the topic to \"%s\"", is->nick, ig->topic);
-	}
-}
-
-void
-icb_cmd_who(struct icb_session *is, char *arg)
-{
-	struct icb_group *ig;
-	char group[ICB_MAXGRPLEN];
-
-	while (strlen(arg) && arg[0] == '-') { /* ignore options, for now */
-		/* ircII "set SHOW_CHANNEL_NAMES ON" uses /w -s */
-		while(arg[0] != ' ' && arg[0] != 0)
-			arg++;
-		if(arg[0] == ' ')
-			arg++;
-	}
-
-	if (strlen(arg) == 0)
-		return icb_who(is, NULL);
-
-	/* pidgin-icb treats '.' as the current group */
-	if (strlen(arg) == 1 && arg[0] == '.') {
-		icb_who(is, is->group);
-		return;
-	}
-
-	icb_vis(group, arg, ICB_MAXGRPLEN, VIS_SP);
-	LIST_FOREACH(ig, &groups, entry) {
-		if (strcmp(ig->name, group) == 0)
-			break;
-	}
-	if (ig == NULL) {
-		icb_error(is, "The group %s doesn't exist.", group);
-		return;
-	}
-	icb_who(is, ig);
-}
Index: s.c
===================================================================
--- dns.c	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,180 +1,0 @@
-/*
- * Copyright (c) 2014 Mike Belopuhov
- * Copyright (c) 2014 Eric Faurot <eric@faurot.net>
- *
- * 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 MIND, 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/types.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <errno.h>
-#include <event.h>
-#include <resolv.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-
-#ifdef __NetBSD__
-#define NO_ASYNC
-#endif
-
-#ifdef NO_ASYNC
-struct asr_result {
-	struct addrinfo* ar_addrinfo;
-	int ar_gai_errno;
-};
-#else
-#include <asr.h>
-#endif
-
-#include "icb.h"
-#include "icbd.h"
-
-void dns_done_host(struct asr_result *, void *);
-void dns_done_reverse(struct asr_result *, void *);
-int  cmp_addr(struct sockaddr *, struct sockaddr *);
-
-extern int dodns;
-
-void
-dns_done_host(struct asr_result *ar, void *arg)
-{
-	struct icb_session *is = arg;
-	struct addrinfo *res;
-	int found = 0;
-
-	if (ISSETF(is->flags, ICB_SF_PENDINGDROP)) {
-		if (ar->ar_addrinfo)
-			freeaddrinfo(ar->ar_addrinfo);
-		free(is);
-		return;
-	}
-
-	if (ar->ar_gai_errno == 0) {
-		if (strncmp(is->hostname, "localhost",
-		    sizeof "localhost" - 1) == 0)
-			strlcpy(is->host, "unknown", ICB_MAXHOSTLEN);
-		else if (strlen(is->hostname) < ICB_MAXHOSTLEN) {
-			for (res = ar->ar_addrinfo; res; res = res->ai_next) {
-				if (cmp_addr(res->ai_addr, (struct sockaddr *)
-				    &is->ss) == 0) {
-					strlcpy(is->host, is->hostname,
-					    ICB_MAXHOSTLEN);
-					found = 1;
-					break;
-				}
-			}
-			if (!found)
-				icbd_log(is, LOG_WARNING, "hostname %s does "
-				   "not resolve back to connecting ip %s",
-				    is->hostname, is->host);
-		}
-	} else
-		icbd_log(is, LOG_DEBUG, "dns resolution failed: %s",
-		    gai_strerror(ar->ar_gai_errno));
-
-	if (ar->ar_addrinfo)
-		freeaddrinfo(ar->ar_addrinfo);
-
-	CLRF(is->flags, ICB_SF_DNSINPROGRESS);
-}
-
-void
-dns_done_reverse(struct asr_result *ar, void *arg)
-{
-	struct icb_session *is = arg;
-#ifdef NO_ASYNC
-	struct asr_result result;
-#else
-	struct asr_query *as;
-#endif
-	struct addrinfo	hints;
-
-	if (ISSETF(is->flags, ICB_SF_PENDINGDROP)) {
-		free(is);
-		return;
-	}
-
-	if (ar->ar_gai_errno == 0) {
-		icbd_log(is, LOG_DEBUG, "reverse dns resolved %s to %s",
-		    is->host, is->hostname);
-		/* try to verify that it resolves back */
-		memset(&hints, 0, sizeof(hints));
-		hints.ai_family = PF_UNSPEC;
-#ifdef NO_ASYNC
-		getaddrinfo(is->hostname, NULL, &hints, &result.ar_addrinfo);
-		result.ar_gai_errno = errno;
-		dns_done_host(&result, is);
-#else
-		as = getaddrinfo_async(is->hostname, NULL, &hints, NULL);
-		event_asr_run(as, dns_done_host, is);
-#endif
-	} else {
-		icbd_log(is, LOG_DEBUG, "reverse dns resolution failed: %s",
-		    gai_strerror(ar->ar_gai_errno));
-		CLRF(is->flags, ICB_SF_DNSINPROGRESS);
-	}
-}
-
-int
-cmp_addr(struct sockaddr *a, struct sockaddr *b)
-{
-	if (a->sa_family != b->sa_family)
-		return (a->sa_family - b->sa_family);
-
-	if (a->sa_family == AF_INET)
-		return (((struct sockaddr_in *)a)->sin_addr.s_addr -
-		    ((struct sockaddr_in *)b)->sin_addr.s_addr);
-
-	if (a->sa_family == AF_INET6)
-		return (memcmp(&((struct sockaddr_in6 *)a)->sin6_addr,
-		    &((struct sockaddr_in6 *)b)->sin6_addr,
-		    sizeof (struct in6_addr)));
-
-	return -1;
-}
-
-void
-dns_resolve(struct icb_session *is)
-{
-#ifdef NO_ASYNC
-	struct asr_result result;
-#else
-	struct asr_query *as;
-#endif
-
-	if (!dodns)
-		return;
-
-	SETF(is->flags, ICB_SF_DNSINPROGRESS);
-
-	if (verbose)
-		icbd_log(is, LOG_DEBUG, "resolving: %s", is->host);
-
-#ifdef NO_ASYNC
-	getnameinfo((struct sockaddr *)&is->ss,
-		    ((struct sockaddr *)&is->ss)->sa_len, is->hostname,
-		    sizeof is->hostname, NULL, 0, NI_NOFQDN);
-	result.ar_gai_errno = errno;
-	dns_done_reverse(&result, is);
-#else
-	as = getnameinfo_async((struct sockaddr *)&is->ss,
-	    ((struct sockaddr *)&is->ss)->sa_len, is->hostname,
-	    sizeof is->hostname, NULL, 0, NI_NOFQDN, NULL);
-	event_asr_run(as, dns_done_reverse, is);
-#endif
-}
-
Index: b.c
===================================================================
--- icb.c	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,792 +1,0 @@
-/*
- * Copyright (c) 2009, 2010, 2013, 2014 Mike Belopuhov
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <netdb.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <event.h>
-#include <vis.h>
-
-#include "icb.h"
-#include "icbd.h"
-
-struct icb_grplist groups;
-
-extern int creategroups;
-extern char srvname[NI_MAXHOST];
-
-void   icb_command(struct icb_session *, char *, char *);
-void   icb_groupmsg(struct icb_session *, char *);
-int    icb_login(struct icb_session *, char *, char *, char *);
-int    icb_dowho(struct icb_session *, struct icb_group *);
-
-/*
- *  icb_init: initialize server name and a list of groups
- */
-void
-icb_init(void)
-{
-	LIST_INIT(&groups);
-
-	if (strlen(srvname) == 0)
-		(void)gethostname(srvname, sizeof srvname);
-	/*
-	 * NI_MAXHOST is usually greater than what we
-	 * can actually send, hence truncation:
-	 */
-	if (strlen(srvname) > 200)
-		srvname[200] = '\0';
-}
-
-/*
- *  icb_start: called upon accepting a new connection, greets new client
- */
-void
-icb_start(struct icb_session *is)
-{
-	icb_sendfmt(is, "%c%c%c%s%c%s", ICB_M_PROTO, '1', ICB_M_SEP, srvname,
-	    ICB_M_SEP, "icbd");
-	SETF(is->flags, ICB_SF_PROTOSENT);
-}
-
-/*
- *  icb_input: main input processing routine
- */
-int
-icb_input(struct icb_session *is)
-{
-	char *msg = is->buffer;
-	int msglen = is->length;
-	unsigned char type;
-	char *wptr = NULL;
-	int res = 0;
-
-	is->last = getmonotime();
-	type = msg[0];
-	msg++;
-	if (!ISSETF(is->flags, ICB_SF_LOGGEDIN) && type != ICB_M_LOGIN) {
-		icb_error(is, "Not logged in");
-		return (0);
-	}
-	switch (type) {
-	case ICB_M_LOGIN: {
-		char client[ICB_MAXNICKLEN];
-		char nick[ICB_MAXNICKLEN];
-		char group[ICB_MAXGRPLEN];
-		char cmd[ICB_MAXCMDLEN];
-
-		memset(client, 0, sizeof client);
-		if (icb_token(msg, msglen, &wptr, client, ICB_MAXNICKLEN,
-		    ICB_M_SEP, 1) < 0) {
-			icb_error(is, "Invalid client");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-		memset(nick, 0, sizeof nick);
-		if (icb_token(msg, msglen, &wptr, nick, ICB_MAXNICKLEN,
-		    ICB_M_SEP, 1) <= 0) {
-			icb_error(is, "Invalid nick");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-		memset(group, 0, sizeof group);
-		if (icb_token(msg, msglen, &wptr, group, ICB_MAXGRPLEN,
-		    ICB_M_SEP, 1) < 0) {
-			icb_error(is, "Invalid login group");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-		memset(cmd, 0, sizeof cmd);
-		if (icb_token(msg, msglen, &wptr, cmd, ICB_MAXCMDLEN,
-		    ICB_M_SEP, 1) < 0) {
-			icb_error(is, "Invalid command");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-		if (strlen(cmd) > 0 && cmd[0] == 'w') {
-			icb_error(is, "Command not implemented");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-		if (strlen(cmd) == 0 || strcmp(cmd, "login") != 0) {
-			icb_error(is, "Malformed login packet");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-		res = icb_login(is, group, nick, client);
-		break;
-	}
-	case ICB_M_OPEN: {
-		icb_groupmsg(is, msg);
-		break;
-	}
-	case ICB_M_COMMAND: {
-		char cmd[ICB_MAXCMDLEN];
-
-		memset(cmd, 0, sizeof cmd);
-		if (icb_token(msg, msglen, &wptr, cmd, ICB_MAXCMDLEN,
-		    ICB_M_SEP, 1) <= 0) {
-			icb_error(is, "Invalid command");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-		msg = wptr;
-		icb_command(is, cmd, msg);
-		break;
-	}
-	case ICB_M_PONG: {
-		icb_sendfmt(is, "%c", ICB_M_PING);
-		break;
-	}
-	case ICB_M_PROTO:
-	case ICB_M_NOOP:
-		/* ignore */
-		break;
-	default:
-		/* everything else is not valid */
-		icb_error(is, "Undefined message type %u", type);
-	}
-	return (res);
-}
-
-/*
- *  icb_login: handles login ('a') packets
- */
-int
-icb_login(struct icb_session *is, char *grp, char *nick, char *client)
-{
-	const char *defgrp = "1";
-	struct icb_group *ig;
-	struct icb_session *s;
-	char group[ICB_MAXGRPLEN];
-
-	if (!nick || strlen(nick) == 0 ||
-	    icb_vis(is->nick, nick, ICB_MAXNICKLEN, VIS_SP)) {
-		icb_error(is, "Invalid nick");
-		icbd_drop(is, NULL);
-		return (1);
-	}
-	if (!grp || strlen(grp) == 0)
-		strlcpy(group, defgrp, ICB_MAXGRPLEN);
-	else
-		icb_vis(group, grp, ICB_MAXGRPLEN, VIS_SP);
-	LIST_FOREACH(ig, &groups, entry) {
-		if (strcmp(ig->name, group) == 0)
-			break;
-	}
-	if (ig == NULL) {
-		if (!creategroups) {
-			icb_error(is, "Can't create new groups", group);
-			icbd_drop(is, NULL);
-			return (1);
-		} else {
-			if ((ig = icb_addgroup(is, group)) == NULL) {
-				icb_error(is, "Can't create group %s", group);
-				return (0);
-			}
-			icbd_log(NULL, LOG_DEBUG, "%s created group %s",
-			    is->nick, group);
-		}
-	}
-	LIST_FOREACH(s, &ig->sess, entry) {
-		if (strcmp(s->nick, is->nick) == 0) {
-			icb_error(is, "Nick is already in use");
-			icbd_drop(is, NULL);
-			return (1);
-		}
-	}
-
-	if (client && strlen(client) > 0)
-		icb_vis(is->client, client, sizeof is->client, VIS_SP);
-	else
-		strlcpy(is->client, is->nick, sizeof is->client);
-	is->group = ig;
-	is->login = time(NULL);
-	is->last = getmonotime();
-
-	/* notify group */
-	icb_status_group(ig, NULL, STATUS_SIGNON, "%s (%s@%s) entered group",
-	    is->nick, is->client, is->host);
-
-	CLRF(is->flags, ICB_SF_PROTOSENT);
-	SETF(is->flags, ICB_SF_LOGGEDIN);
-
-	LIST_INSERT_HEAD(&ig->sess, is, entry);
-
-	/* acknowledge successful login */
-	icb_sendfmt(is, "%c", ICB_M_LOGIN);
-
-	/* notify user */
-	icb_status(is, STATUS_STATUS, "You are now in group %s%s", ig->name,
-	    icb_ismod(ig, is) ? " as moderator" : "");
-
-	/* send user a topic name */
-	if (strlen(ig->topic) > 0)
-		icb_status(is, STATUS_TOPIC, "Topic for %s is \"%s\"",
-		    ig->name, ig->topic);
-	return (0);
-}
-
-/*
- *  icb_groupmsg: handles open message ('b') packets
- */
-void
-icb_groupmsg(struct icb_session *is, char *msg)
-{
-	char buf[ICB_MSGSIZE];
-	struct icb_group *ig = is->group;
-	struct icb_session *s;
-	int res, buflen;
-
-	if (strlen(msg) == 0) {
-		icb_error(is, "Empty message");
-		return;
-	}
-
-	do {
-		res = snprintf(&buf[1], sizeof buf - 1, "%c%s%c%s", ICB_M_OPEN,
-		    is->nick, ICB_M_SEP, msg);
-		if (res < 0) {
-			icbd_log(is, LOG_ERR, "Format error in %s", __func__);
-			return;
-		}
-		/* res doesn't include the terminating NUL */
-		buflen = MIN((size_t)res + 1, sizeof buf - 1);
-		buf[0] = buflen;
-
-		logger(ig->name, is->nick, msg);
-
-		LIST_FOREACH(s, &ig->sess, entry) {
-			if (s == is)
-				continue;
-			icbd_send(s, buf, buflen + 1);
-		}
-
-		msg += buflen - 1;
-	} while (res > buflen - 1);
-}
-
-/*
- *  icb_privmsg: handles personal message ('c') packets
- */
-void
-icb_privmsg(struct icb_session *is, char *to, char *msg)
-{
-	struct icb_group *ig = is->group;
-	struct icb_session *s;
-	char buf[ICB_MSGSIZE];
-	char whom[ICB_MAXNICKLEN];
-	int res, buflen;
-
-	icb_vis(whom, to, ICB_MAXNICKLEN, VIS_SP);
-
-	/* try home group first */
-	LIST_FOREACH(s, &ig->sess, entry) {
-		if (strcmp(s->nick, whom) == 0)
-			break;
-	}
-	if (!s) {
-		/* try all groups until the first match */
-		LIST_FOREACH(ig, &groups, entry) {
-			LIST_FOREACH(s, &ig->sess, entry) {
-				if (strcmp(s->nick, whom) == 0)
-					break;
-			}
-			if (s)
-				break;
-		}
-		if (!s) {
-			icb_error(is, "No such user %s", whom);
-			return;
-		}
-	}
-
-	do {
-		res = snprintf(&buf[1], sizeof buf - 1, "%c%s%c%s",
-		    ICB_M_PERSONAL, is->nick, ICB_M_SEP, msg);
-		if (res < 0) {
-			icbd_log(is, LOG_ERR, "Format error in %s", __func__);
-			return;
-		}
-		/* res doesn't include the terminating NUL */
-		buflen = MIN((size_t)res + 1, sizeof buf - 1);
-		buf[0] = buflen;
-
-		icbd_send(s, buf, buflen + 1);
-
-		msg += buflen - 1;
-	} while (res > buflen - 1);
-}
-
-/*
- *  icb_command: handles command ('h') packets
- */
-void
-icb_command(struct icb_session *is, char *cmd, char *arg)
-{
-	void (*handler)(struct icb_session *, char *);
-	char command[ICB_MAXCMDLEN];
-
-	icb_vis(command, cmd, sizeof command, VIS_SP);
-
-	if ((handler = icb_cmd_lookup(command)) == NULL) {
-		icb_error(is, "Unsupported command: %s", command);
-		return;
-	}
-	handler(is, arg);
-}
-
-/*
- *  icb_cmdout: sends out command output ('i') packets, called from the
- *              command handlers
- */
-void
-icb_cmdout(struct icb_session *is, int type, char *outmsg)
-{
-	char *otype = NULL;
-
-	switch (type) {
-	case CMDOUT_CO:
-		otype = "co";
-		break;
-	case CMDOUT_EC:
-		otype = "ec";
-		break;
-	case CMDOUT_WG:
-		otype = "wg";
-		break;
-	case CMDOUT_WH:
-		otype = "wh";
-		break;
-	case CMDOUT_WL:
-		otype = "wl";
-		break;
-	default:
-		icbd_log(is, LOG_ERR, "unknown cmdout type %d", type);
-		return;
-	}
-	if (outmsg)
-		icb_sendfmt(is, "%c%s%c%s", ICB_M_CMDOUT, otype, ICB_M_SEP,
-		    outmsg);
-	else
-		icb_sendfmt(is, "%c%s", ICB_M_CMDOUT, otype);
-}
-
-/*
- *  icb_status: sends a status message ('d') to the client
- */
-void
-icb_status(struct icb_session *is, int type, const char *fmt, ...)
-{
-	va_list ap;
-	char buf[ICB_MSGSIZE];
-	int res, buflen;
-	static const struct {
-		int		 type;
-		const char	*msg;
-	} msgtab[] = {
-		{ STATUS_ARRIVE,	"Arrive" },
-		{ STATUS_BOOT,		"Boot" },
-		{ STATUS_DEPART,	"Depart" },
-		{ STATUS_HELP,		"Help" },
-		{ STATUS_NAME,		"Name" },
-		{ STATUS_NOBEEP,	"No-Beep" },
-		{ STATUS_NOTIFY,	"Notify" },
-		{ STATUS_SIGNON,	"Sign-on" },
-		{ STATUS_SIGNOFF,	"Sign-off" },
-		{ STATUS_STATUS,	"Status" },
-		{ STATUS_TOPIC,		"Topic" },
-		{ STATUS_WARNING,	"Warning" },
-		{ 0,			NULL }
-	};
-
-	if (type < 0 || type > (int)nitems(msgtab) - 1)
-		return;
-	res = snprintf(&buf[1], sizeof buf - 1, "%c%s%c", ICB_M_STATUS,
-	    msgtab[type].msg, ICB_M_SEP);
-	if (res < 0) {
-		icbd_log(NULL, LOG_ERR, "Format error in %s", __func__);
-		return;
-	}
-	if ((size_t)res >= sizeof buf) {
-		icbd_log(NULL, LOG_ERR, "Status buffer too small");
-		return;
-	}
-	buflen = MIN((size_t)res + 1, sizeof buf - 1);
-	va_start(ap, fmt);
-	res = vsnprintf(&buf[buflen], sizeof buf - buflen - 1, fmt, ap);
-	va_end(ap);
-	buflen--; /* buf[buflen] was overwritten */
-	if (res < 0) {
-		icbd_log(NULL, LOG_ERR, "Message format error in %s", __func__);
-		return;
-	}
-	if ((size_t)res + buflen >= sizeof buf) {
-		icbd_log(NULL, LOG_ERR, "Status message too long");
-		return;
-	}
-	buflen += MIN((size_t)res + 1, sizeof buf - buflen - 1);
-	buf[0] = buflen;
-	icbd_send(is, buf, buflen + 1);
-}
-
-/*
- *  icb_status: sends a status message ('d') to the group except of the
- *              "ex" if it's not NULL
- */
-void
-icb_status_group(struct icb_group *ig, struct icb_session *ex, int type,
-    const char *fmt, ...)
-{
-	char buf[ICB_MSGSIZE - 10]; /* truncate to make sure all fits */
-	va_list ap;
-	struct icb_session *s;
-
-	va_start(ap, fmt);
-	(void)vsnprintf(buf, sizeof buf, fmt, ap);
-	LIST_FOREACH(s, &ig->sess, entry) {
-		if (ex && s == ex)
-			continue;
-		icb_status(s, type, buf);
-	}
-	logger(ig->name, "", buf);
-	icbd_log(NULL, LOG_DEBUG, "%s", buf);
-	va_end(ap);
-}
-
-/*
- *  icb_error: sends an error message ('e') to the client
- */
-void
-icb_error(struct icb_session *is, const char *fmt, ...)
-{
-	char buf[ICB_MSGSIZE];
-	va_list ap;
-	int res, buflen;
-
-	va_start(ap, fmt);
-	res = vsnprintf(&buf[2], sizeof buf - 2, fmt, ap);
-	va_end(ap);
-	if (res < 0) {
-		icbd_log(NULL, LOG_ERR, "Format error");
-		return;
-	}
-	buflen = MIN((size_t)res + 1, sizeof buf - 2);
-	buf[0] = ++buflen; /* account for ICB_M_ERROR */
-	buf[1] = ICB_M_ERROR;
-	icbd_send(is, buf, buflen + 1);
-	icbd_log(is, LOG_DEBUG, "%s", buf + 2);
-}
-
-/*
- *  icb_remove: removes a session from the associated group
- */
-void
-icb_remove(struct icb_session *is, char *reason)
-{
-	if (is->group) {
-		if (icb_ismod(is->group, is))
-			(void)icb_pass(is->group, is, NULL);
-		LIST_REMOVE(is, entry);
-		if (reason)
-			icb_status_group(is->group, NULL, STATUS_SIGNOFF,
-			    "%s (%s@%s) just left: %s", is->nick, is->client,
-			    is->host, reason);
-		else
-			icb_status_group(is->group, NULL, STATUS_SIGNOFF,
-			    "%s (%s@%s) just left", is->nick, is->client,
-			    is->host);
-		is->group = NULL;
-	}
-}
-
-/*
- *  icb_addgroup: adds a new group to the list
- */
-struct icb_group *
-icb_addgroup(struct icb_session *is, char *name)
-{
-	struct icb_group *ig;
-
-	if ((ig = calloc(1, sizeof *ig)) == NULL)
-		return (NULL);
-	strlcpy(ig->name, name, sizeof ig->name);
-	if (is)
-		ig->mod = is;
-	LIST_INIT(&ig->sess);
-	LIST_INSERT_HEAD(&groups, ig, entry);
-	return (ig);
-}
-
-#ifdef notused
-/*
- *  icb_delgroup: removes a group from the list
- */
-void
-icb_delgroup(struct icb_group *ig)
-{
-	struct icb_session *s;
-
-	/* well, i guess we should kick out participants! ;-) */
-	LIST_FOREACH(s, &ig->sess, entry) {
-		icb_status(s, STATUS_WARNING, "Group dismissed");
-		s->group = NULL;
-	}
-	LIST_REMOVE(ig, entry);
-	bzero(ig, sizeof ig);	/* paranoic thing, obviously */
-	free(ig);
-}
-#endif
-
-/*
- *  icb_dowho: a helper function that sends out a group header as a command
- *             output and user information in the "wl" format
- */
-int
-icb_dowho(struct icb_session *is, struct icb_group *ig)
-{
-	char buf[ICB_MSGSIZE - 10]; /* truncate to make sure all fits */
-	struct icb_session *s;
-	time_t now;
-	int nusers = 0;
-
-	now = getmonotime();
-	icb_cmdout(is, CMDOUT_CO, " ");
-	snprintf(buf, sizeof buf, "Group: %-8s (%cvl) Mod: %-13s Topic: %s",
-	    ig->name, ig->mod ? 'm' : 'p', ig->mod ? ig->mod->nick : "(None)",
-	    strlen(ig->topic) > 0 ? ig->topic : "(None)");
-	icb_cmdout(is, CMDOUT_CO, buf);
-	LIST_FOREACH(s, &ig->sess, entry) {
-		(void)snprintf(buf, sizeof buf,
-#ifdef __NetBSD__
-		    "%c%c%s%c%ld%c0%c%ld%c%s%c%s%c%s",
-#else
-		    "%c%c%s%c%lld%c0%c%lld%c%s%c%s%c%s",
-#endif
-		    icb_ismod(ig, s) ? 'm' : ' ', ICB_M_SEP,
-		    s->nick, ICB_M_SEP, now - s->last,
-		    ICB_M_SEP, ICB_M_SEP, s->login, ICB_M_SEP,
-		    s->client, ICB_M_SEP, s->host, ICB_M_SEP, " ");
-		icb_cmdout(is, CMDOUT_WL, buf);
-		nusers++;
-	}
-	return (nusers);
-}
-
-/*
- *  icb_who: sends a list of users of either the specified group or all
- *           groups found on the server
- */
-void
-icb_who(struct icb_session *is, struct icb_group *ig)
-{
-	char buf[ICB_MSGSIZE - 10]; /* truncate to make sure all fits */
-	struct icb_group *g;
-
-	if (!ig) {
-		int nusers = 0, ngroups = 0;
-
-		LIST_FOREACH(g, &groups, entry) {
-			nusers += icb_dowho(is, g);
-			ngroups++;
-		}
-		if (nusers > 0) {
-			(void)snprintf(buf, sizeof buf,
-			    "Total: %d %s in %d %s",
-			    nusers, nusers > 1 ? "users" : "user",
-			    ngroups, ngroups > 1 ? "groups" : "group");
-		} else
-			(void)snprintf(buf, sizeof buf, "No users found.");
-		icb_cmdout(is, CMDOUT_CO, buf);
-	} else
-		(void)icb_dowho(is, ig);
-}
-
-/*
- *  icb_ismod: checks whether group is moderated by "is"
- */
-int
-icb_ismod(struct icb_group *ig, struct icb_session *is)
-{
-	return (ig->mod == is);
-}
-
-/*
- *  icb_modpermit: checks user against the moderators table if it has
- *                 been populated
- */
-int
-icb_modpermit(struct icb_session *is, int enforce)
-{
-	extern char modtab[ICB_MTABLEN][ICB_MAXNICKLEN];
-	extern int modtabcnt;
-
-	icbd_modupdate();
-	if ((enforce ? 0 : modtabcnt == 0) ||
-	    bsearch(is->nick, modtab, modtabcnt, ICB_MAXNICKLEN,
-	    (int (*)(const void *, const void *))strcmp))
-		return (1);
-	return (0);
-}
-
-/*
- *  icb_pass: passes moderation of group "ig" from "from" to "to",
- *            returns -1 if "from" is not a moderator, 1 if passed
- *            to "to" and 0 otherwise (no moderator or passed to the
- *            internal bot)
- */
-int
-icb_pass(struct icb_group *ig, struct icb_session *from,
-    struct icb_session *to)
-{
-	if (ig->mod && ig->mod != from)
-		return (-1);
-	if (!from && !to)
-		return (-1);
-	ig->mod = to;
-	if (to)
-		icb_status(to, STATUS_NOTIFY, "%s just passed you moderation"
-		    " of %s", from ? from->nick : "server", ig->name);
-	icb_status_group(ig, to, STATUS_NOTIFY, "%s has passed moderation "
-	    "to %s", from ? from->nick : "server", to ? to->nick : "server");
-	return (1);
-}
-
-/*
- *  icb_sendfmt: formats a string and sends it over
- */
-void
-icb_sendfmt(struct icb_session *is, const char *fmt, ...)
-{
-	char buf[ICB_MSGSIZE];
-	va_list ap;
-	int res, buflen;
-
-	va_start(ap, fmt);
-	res = vsnprintf(&buf[1], sizeof buf - 1, fmt, ap);
-	va_end(ap);
-	if (res < 0) {
-		icbd_log(NULL, LOG_ERR, "Format error in %s", __func__);
-		return;
-	}
-	buflen = MIN((size_t)res + 1, sizeof buf - 1);
-	buf[0] = buflen;
-	icbd_send(is, buf, buflen + 1);
-}
-
-/*
- *  icb_token: copies a sequence of characters delimited by the 'sep' character
- *             from the source buffer 'buf' at offset indicated by 'bufptr' to
- *             the destination buffer 'dst' and sets 'bufptr' to the next byte
- *             after 'sep'.
- */
-int
-icb_token(char *buf, int len, char **bufptr, char *dst, int dstlen, int sep,
-    int trim)
-{
-	char *start;
-	int i, ret;
-
-	if (buf == NULL || len <= 0 || dst == NULL || dstlen <= 0)
-		return (0);
-	if (*bufptr == NULL)
-		*bufptr = buf;
-	start = *bufptr;
-	for (i = *bufptr - buf; i < len; i++, (*bufptr)++) {
-		if (**bufptr == sep || **bufptr == '\0') {
-			/* copy and null terminate the token */
-			ret = strlcpy(dst, start,
-			    MIN(*bufptr - start + 1, dstlen));
-			if (**bufptr != '\0')
-				(*bufptr)++;
-			if (ret > 0 && trim)
-				ret = icb_trim(dst, dstlen);
-			return (ret);
-		}
-	}
-	/*
-	 * Reached the end of the buffer without finding a field separator
-	 * nor the end of line character.  If we have advanced our pointer
-	 * we should copy the resulting single field out.
-	 */
-	if (*bufptr - start > 0) {
-		ret = strlcpy(dst, start, MIN(*bufptr - start + 1, dstlen));
-		if (ret > 0 && trim)
-			ret = icb_trim(dst, dstlen);
-		return (ret);
-	}
-	return (0);
-}
-
-/*
- *  icb_trim: trims trailing whitespace
- */
-int
-icb_trim(char *buf, int len)
-{
-	char *p = buf;
-	int i;
-
-	for (i = 0; i < len && *p != '\0'; i++)
-		p++;
-	if (*p == '\0' && p - buf > 0)
-		p--;
-	while (p >= buf && isspace(*p)) {
-		*p = '\0';
-		i--;
-		if (p > buf)
-			p--;
-	}
-	return (i);
-}
-
-/*
- *  icb_vis: strnvis-like function that escapes percentages as well
- */
-int
-icb_vis(char *dst, const char *src, size_t dstsize, int flags)
-{
-	int si, di, td;
-
-	for (si = 0, di = 0; (size_t)di < dstsize - 1 && src[si] != '\0';
-	    si++, di++) {
-		if (src[si] == '%') {
-			if ((size_t)di + 1 >= dstsize - 1)
-				break;
-			dst[di++] = '%';
-			dst[di] = '%';
-		} else if (src[si] == ' ' && flags & VIS_SP)
-			dst[di] = '_';
-		else if (isgraph(src[si]) || src[si] == ' ')
-			dst[di] = src[si];
-		else {
-			td = snprintf(&dst[di], dstsize - di,
-			    "\\%03o", (unsigned char)src[si]);
-			if (td == -1 || (size_t)td >= dstsize - di)
-				break;
-			di += td - 1;
-		}
-	}
-	dst[MIN((size_t)di, dstsize - 1)] = '\0';
-	return (0);
-}
Index: b.h
===================================================================
--- icb.h	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,147 +1,0 @@
-/*
- * Copyright (c) 2009 Mike Belopuhov
- *
- * 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 <sys/queue.h>
-#include <sys/socket.h>
-
-/*
- * ICB packet has the following format: <length><type><data>
- * <lenght> is one byte length of the packet excluding the <lenght> byte;
- * <type> is one byte type of the packet;
- * <data> might not be null-terminated.
- */
-#define ICB_MSGSIZE		 256
-
-#define ICB_MAXGRPLEN		 32
-#define ICB_MAXNICKLEN		 32
-#define ICB_MAXTOPICLEN		 160
-#define ICB_MAXHOSTLEN		 40
-#define ICB_MAXCMDLEN		 32
-#define ICB_MTABLEN		 50 /* XXX */
-
-#define ICB_M_LOGIN		 'a'
-#define ICB_M_OPEN		 'b'
-#define ICB_M_PERSONAL		 'c'
-#define ICB_M_STATUS		 'd'
-enum {
-	 STATUS_ARRIVE,
-	 STATUS_BOOT,
-	 STATUS_DEPART,
-	 STATUS_HELP,
-	 STATUS_NAME,
-	 STATUS_NOBEEP,
-	 STATUS_NOTIFY,
-	 STATUS_SIGNON,
-	 STATUS_SIGNOFF,
-	 STATUS_STATUS,
-	 STATUS_TOPIC,
-	 STATUS_WARNING
-};
-#define ICB_M_ERROR		 'e'
-#define ICB_M_IMPORTANT		 'f'
-#define ICB_M_EXIT		 'g'
-#define ICB_M_COMMAND		 'h'
-#define ICB_M_CMDOUT		 'i'
-enum {
-	 CMDOUT_CO,
-	 CMDOUT_EC,
-	 CMDOUT_WG,
-	 CMDOUT_WH,
-	 CMDOUT_WL,
-};
-#define ICB_M_PROTO		 'j'
-#define ICB_M_BEEP		 'k'
-#define ICB_M_PING		 'l'
-#define ICB_M_PONG		 'm'
-#define ICB_M_NOOP		 'n'
-
-#define ICB_M_SEP		 '\001'
-
-struct icb_group;
-
-struct icb_session {
-	char			 nick[ICB_MAXNICKLEN];
-	char			 client[ICB_MAXNICKLEN];
-	char			 host[ICB_MAXHOSTLEN];
-	char			 hostname[NI_MAXHOST];
-	char			 buffer[ICB_MSGSIZE];
-	struct sockaddr_storage	 ss;
-	struct event		 ev;
-	struct bufferevent	*bev;
-	struct icb_group	*group;
-	size_t			 length;
-	size_t			 rlen;
-	time_t			 login;
-	time_t			 last;
-	int			 port;
-	uint32_t		 flags;
-#define SETF(t, f)		 ((t) |= (f))
-#define CLRF(t, f)		 ((t) &= ~(f))
-#define ISSETF(t, f)		 ((t) & (f))
-#define ICB_SF_PROTOSENT	 0x0001
-#define ICB_SF_LOGGEDIN		 0x0002
-#define ICB_SF_NOGROUP		 0x0008
-#define ICB_SF_NOBEEP		 0x0010
-#define ICB_SF_NOBEEP2		 0x0020
-
-#define ICB_SF_DNSINPROGRESS	 0x1000
-#define ICB_SF_PENDINGDROP	 0x2000
-
-	/* in-group linkage */
-	LIST_ENTRY(icb_session)	 entry;
-};
-
-struct icb_group {
-	char			 name[ICB_MAXGRPLEN];
-	char			 topic[ICB_MAXTOPICLEN];
-	LIST_ENTRY(icb_group)	 entry;
-	LIST_HEAD(, icb_session) sess;
-	struct icb_session	*mod;
-};
-
-LIST_HEAD(icb_grplist, icb_group);
-extern struct icb_grplist groups;
-
-#ifndef nitems
-#define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
-#endif
-
-/* cmd.c */
-void *		icb_cmd_lookup(char *);
-
-/* icb.c */
-struct icb_group *
-		icb_addgroup(struct icb_session *, char *);
-void		icb_cmdout(struct icb_session *, int, char *);
-void		icb_delgroup(struct icb_group *);
-void		icb_error(struct icb_session *, const char *, ...);
-void		icb_init(void);
-int		icb_input(struct icb_session *);
-int		icb_ismod(struct icb_group *, struct icb_session *);
-int		icb_modpermit(struct icb_session *, int);
-int		icb_pass(struct icb_group *, struct icb_session *,
-		    struct icb_session *);
-void		icb_privmsg(struct icb_session *, char *, char *);
-void		icb_remove(struct icb_session *, char *);
-void		icb_sendfmt(struct icb_session *, const char *, ...);
-void		icb_start(struct icb_session *);
-void		icb_status(struct icb_session *, int, const char *, ...);
-void		icb_status_group(struct icb_group *, struct icb_session *,
-		    int, const char *, ...);
-void		icb_who(struct icb_session *, struct icb_group *);
-int		icb_token(char *, int, char **, char *, int, int, int);
-int		icb_trim(char *, int);
-int		icb_vis(char *, const char *, size_t, int);
Index: bd.8
===================================================================
--- icbd.8	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,113 +1,0 @@
-.\"
-.\" Copyright (c) 2009 Mike Belopuhov
-.\"
-.\" 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.
-.\"
-.Dd $Mdocdate: April 27 2009 $
-.Dt ICBD 8
-.Os
-.Sh NAME
-.Nm icbd
-.Nd "Internet Citizen's Band protocol daemon"
-.Sh SYNOPSIS
-.Nm icbd
-.Bk -words
-.Op Fl 46Cdnv
-.Oo
-.Fl G Ar group1 Ns Op , Ns Ar ...
-.Oc
-.Op Fl L Ar prefix
-.Op Fl M Ar modtab
-.Op Fl S Ar name
-.Sm off
-.Oo
-.Ar addr Op : Ns Ar port
-.Ar \ ...
-.Oc
-.Sm on
-.Ek
-.Sh DESCRIPTION
-.Nm
-is an Internet Citizen's Band
-.Pq ICB
-protocol daemon which allows peoples to chat online.
-.Pp
-Please refer to the document specified in the
-.Sx SEE ALSO
-section for more information about the ICB protocol.
-.Pp
-The options are as follows:
-.Bl -tag -width "-G group"
-.It Fl 4
-Bind to IPv4 addresses only.
-.It Fl 6
-Bind to IPv6 addresses only.
-.It Fl C
-Allow users to create groups.
-Please note, that everyone creating a new group becomes its moderator.
-.It Fl d
-Do not daemonize.
-If this option is specified,
-.Nm
-will run in the foreground and log to
-.Dv stderr .
-.It Fl G Xo
-.Ar group1 Ns Op , Ns Ar ...
-.Xc
-Instruct
-.Nm
-to create specified groups on startup.
-.It Fl L Ar prefix
-Enables logging of all public messages in all groups and specifies a
-directory inside the chroot that is owned and is writable by the
-.Nm
-user.
-The server will create subdirectories matching those of the group names
-and place log files inside one file per month.
-.It Fl M Ar modtab
-Specifies a moderator table that can be used to restrict users who
-can be granted with moderation of any group.
-The
-.Ar modtab
-file contains one nick per line; empty lines and lines starting with
-a hash symbol are ignored.
-It's located inside the chroot.
-Every time a moderator check is performed,
-.Nm
-checks the modification time of the file and reloads the table if
-any changes have taken place since the last call.
-.It Fl n
-Disable DNS resolver.
-.It Fl S Ar name
-Set the server's name to
-.Ar name .
-.It Fl v
-Produce more verbose output.
-.El
-.Pp
-A list of addresses and/or ports to bind to is specified after all arguments.
-By default,
-.Nm
-will try to listen on all interfaces using
-.Em icb
-protocol port number specified in
-.Pa /etc/services .
-.Sh SEE ALSO
-.Rs
-.%T ICB Protocol
-.%U ftp://ftp.icb.net/pub/icb/src/icbd/Protocol.html
-.Re
-.Sh AUTHORS
-The
-.Nm
-program was written by Mike Belopuhov.
Index: bd.c
===================================================================
--- icbd.c	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,622 +1,0 @@
-/*
- * Copyright (c) 2009 Mike Belopuhov
- * Copyright (c) 2007 Oleg Safiullin
- * Copyright (c) 2024 Nishi
- * Copyright (C) 2025 Izuru Yakumo
- *
- * 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 <sys/types.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <netinet/in_systm.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <sysexits.h>
-#include <syslog.h>
-#include <pwd.h>
-#include <locale.h>
-#include <ctype.h>
-#include <netdb.h>
-#include <event.h>
-#include <errno.h>
-#include <err.h>
-#include <resolv.h>
-
-#include "icb.h"
-#include "icbd.h"
-
-struct stat modtabst;
-char modtabpath[PATH_MAX];
-char modtab[ICB_MTABLEN][ICB_MAXNICKLEN];
-int  modtabcnt;
-char srvname[NI_MAXHOST];
-int  creategroups;
-int  foreground;
-char logprefix[PATH_MAX/2];
-int  dodns = 1;
-int  dologging;
-int  verbose;
-
-void usage(void);
-void getpeerinfo(struct icb_session *);
-void icbd_accept(int, short, void *);
-void icbd_paused(int, short, void *);
-void icbd_drop(struct icb_session *, char *);
-void icbd_ioerr(struct bufferevent *, short, void *);
-void icbd_dispatch(struct bufferevent *, void *);
-void icbd_log(struct icb_session *, int, const char *, ...);
-void icbd_restrict(void);
-void icbd_send(struct icb_session *, char *, ssize_t);
-
-struct icbd_listener {
-	struct event ev, pause;
-};
-
-int
-main(int argc, char *argv[])
-{
-	const char *cause = NULL;
-	int ch, nsocks = 0, save_errno = 0;
-	int inet4 = 0, inet6 = 0;
-	char group[ICB_MAXGRPLEN], *grplist = NULL;
-	char *ptr = NULL;
-
-	/* init group lists before calling icb_addgroup */
-	icb_init();
-
-	while ((ch = getopt(argc, argv, "46CdG:M:nL:S:v")) != -1)
-		switch (ch) {
-		case '4':
-			inet4++;
-			break;
-		case '6':
-			inet6++;
-			break;
-		case 'C':
-			creategroups++;
-			break;
-		case 'd':
-			foreground++;
-			break;
-		case 'G':
-			grplist = optarg;
-			break;
-		case 'L':
-			strlcpy(logprefix, optarg, sizeof logprefix);
-			dologging++;
-			break;
-		case 'M':
-			strlcpy(modtabpath, optarg, sizeof modtabpath);
-			break;
-		case 'n':
-			dodns = 0;
-			break;
-		case 'S':
-			strlcpy(srvname, optarg, sizeof srvname);
-			break;
-		case 'v':
-			verbose++;
-			break;
-		default:
-			usage();
-			/* NOTREACHED */
-		}
-	argc -= optind;
-	argv += optind;
-
-	/* add group "1" as it's a login group for most of the clients */
-	if (icb_addgroup(NULL, "1") == NULL)
-		err(EX_UNAVAILABLE, NULL);
-
-	if (grplist) {
-		while (icb_token(grplist, strlen(grplist), &ptr, group,
-		    ICB_MAXGRPLEN, ',', 0) > 0)
-			if (icb_addgroup(NULL, group) == NULL)
-				err(EX_UNAVAILABLE, NULL);
-	}
-
-	if (argc == 0)
-		argc++;
-
-	if (inet4 && inet6)
-		errx(EX_USAGE, "Can't specify both -4 and -6");
-
-	tzset();
-	(void)setlocale(LC_ALL, "C");
-
-	if (foreground)
-		openlog("icbd", LOG_PID | LOG_PERROR, LOG_DAEMON);
-	else
-		openlog("icbd", LOG_PID | LOG_NDELAY, LOG_DAEMON);
-
-	if (!foreground && daemon(0, 0) < 0)
-		err(EX_OSERR, NULL);
-
-	(void)event_init();
-
-	for (ch = 0; ch < argc; ch++) {
-		struct addrinfo hints, *res, *res0;
-		struct icbd_listener *l;
-		char *addr, *port;
-		int error, s, on = 1;
-
-		addr = port = NULL;
-		if (argv[ch] != NULL) {
-			if (argv[ch][0] != ':')
-				addr = argv[ch];
-			if ((port = strrchr(argv[ch], ':')) != NULL)
-				*port++ = '\0';
-		}
-
-		bzero(&hints, sizeof hints);
-		if (inet4 || inet6)
-			hints.ai_family = inet4 ? PF_INET : PF_INET6;
-		else
-			hints.ai_family = PF_UNSPEC;
-		hints.ai_socktype = SOCK_STREAM;
-		hints.ai_flags = AI_PASSIVE;
-#ifdef __OpenBSD__
-		/* Apparently OpenBSD is the only one that has icb on /etc/services */
-		/* Sure, it could be easily added to any other system, but I'm personally against it */
-		/* ~Izuru Yakumo */
-		if ((error = getaddrinfo(addr, port ? port : "icb", &hints,
-		    &res0)) != 0) {
-			syslog(LOG_ERR, "%s", gai_strerror(error));
-			return (EX_UNAVAILABLE);
-		}
-#else
-		if ((error = getaddrinfo(addr, port ? port : "7326", &hints, &res0)) != 0) {
-			syslog(LOG_ERR, "%s", gai_strerror(error));
-			return (EX_UNAVAILABLE);
-		}
-#endif
-		for (res = res0; res != NULL; res = res->ai_next) {
-			if ((s = socket(res->ai_family, res->ai_socktype,
-			    res->ai_protocol)) < 0) {
-				cause = "socket";
-				save_errno = errno;
-				continue;
-			}
-
-			if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on,
-			    sizeof on) < 0) {
-				cause = "SO_REUSEADDR";
-				save_errno = errno;
-				(void)close(s);
-				continue;
-			}
-
-			if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
-				cause = "bind";
-				save_errno = errno;
-				(void)close(s);
-				continue;
-			}
-
-			(void)listen(s, TCP_BACKLOG);
-
-			if ((l = calloc(1, sizeof *l)) == NULL)
-				err(EX_UNAVAILABLE, NULL);
-			event_set(&l->ev, s, EV_READ | EV_PERSIST,
-			    icbd_accept, l);
-			if (event_add(&l->ev, NULL) < 0) {
-				syslog(LOG_ERR, "event_add: %m");
-				return (EX_UNAVAILABLE);
-			}
-			evtimer_set(&l->pause, icbd_paused, l);
-
-			nsocks++;
-		}
-
-		freeaddrinfo(res0);
-	}
-
-	if (nsocks == 0) {
-		errno = save_errno;
-		syslog(LOG_ERR, "%s: %m", cause);
-		return (EX_UNAVAILABLE);
-	}
-
-	/* start the logger service */
-	logger_init();
-
-	/* initialize resolver */
-	res_init();
-
-	icbd_restrict();
-
-	icbd_modupdate();
-
-	(void)signal(SIGPIPE, SIG_IGN);
-
-	(void)event_dispatch();
-
-	syslog(LOG_ERR, "event_dispatch: %m");
-
-	return (EX_UNAVAILABLE);
-}
-
-void
-icbd_accept(int fd, short event __attribute__((__unused__)),
-    void *arg)
-{
-	struct icbd_listener *l = arg;
-	struct sockaddr_storage ss;
-	struct timeval p = { 1, 0 };
-	struct icb_session *is;
-	socklen_t ss_len = sizeof ss;
-	int s, on = 1, tos = IPTOS_LOWDELAY;
-
-	ss.ss_len = ss_len;
-	s = accept(fd, (struct sockaddr *)&ss, &ss_len);
-	if (s == -1) {
-		switch (errno) {
-		case EINTR:
-		case EWOULDBLOCK:
-		case ECONNABORTED:
-			return;
-		case EMFILE:
-		case ENFILE:
-			event_del(&l->ev);
-			evtimer_add(&l->pause, &p);
-			return;
-		default:
-			syslog(LOG_ERR, "accept: %m");
-			return;
-		}
-	}
-
-	if (ss.ss_family == AF_INET)
-		if (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof tos) < 0)
-			syslog(LOG_WARNING, "IP_TOS: %m");
-	if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof on) < 0)
-		syslog(LOG_WARNING, "SO_KEEPALIVE: %m");
-	if ((is = calloc(1, sizeof *is)) == NULL) {
-		syslog(LOG_ERR, "calloc: %m");
-		(void)close(s);
-		return;
-	}
-	if ((is->bev = bufferevent_new(s, icbd_dispatch, NULL, icbd_ioerr,
-	    is)) == NULL) {
-		syslog(LOG_ERR, "bufferevent_new: %m");
-		(void)close(s);
-		free(is);
-		return;
-	}
-	if (bufferevent_enable(is->bev, EV_READ)) {
-		syslog(LOG_ERR, "bufferevent_enable: %m");
-		(void)close(s);
-		bufferevent_free(is->bev);
-		free(is);
-		return;
-	}
-
-	/* save host information */
-	getpeerinfo(is);
-
-	/* start icb conversation */
-	icb_start(is);
-}
-
-void
-icbd_paused(int fd __attribute__((__unused__)),
-	short events __attribute__((__unused__)), void *arg)
-{
-	struct icbd_listener *l = arg;
-	event_add(&l->ev, NULL);
-}
-
-__dead void
-usage(void)
-{
-	extern char *__progname;
-
-	(void)fprintf(stderr, "usage: %s [-46Cdv] [-G group1[,group2,...]] "
-	   "[-L prefix] [-M modtab]\n\t[-S name] [[addr][:port] ...]\n",
-	    __progname);
-	exit(EX_USAGE);
-}
-
-/*
- *  bufferevent functions
- */
-void
-icbd_ioerr(struct bufferevent *bev __attribute__((__unused__)), short what,
-    void *arg)
-{
-	struct icb_session *is = (struct icb_session *)arg;
-
-	if (what & EVBUFFER_TIMEOUT)
-		icbd_drop(is, "timeout");
-	else if (what & EVBUFFER_EOF)
-		icbd_drop(is, NULL);
-	else if (what & EVBUFFER_ERROR)
-		icbd_drop(is, (what & EVBUFFER_READ) ? "read error" :
-		    "write error");
-}
-
-void
-icbd_dispatch(struct bufferevent *bev, void *arg)
-{
-	struct icb_session *is = (struct icb_session *)arg;
-	unsigned char length;
-	size_t res;
-
-	while (EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)) > 0) {
-		if (is->length == 0) {
-			/* read length */
-			bufferevent_read(bev, &length, 1);
-			if (length == 0) {
-				/*
-				 * An extension has been proposed:
-				 * if length is 0, the packet is part of an
-				 * "extended packet". The packet should be
-				 * treated as if length was 255 and the next
-				 * packet received from the sender should be
-				 * appended to this packet.
-				 *
-				 * This server doesn't support this yet.
-				 */
-				icbd_drop(is, "invalid packet");
-				return;
-			}
-			is->length = (size_t)length;
-			is->rlen = 0;
-		}
-		/* read as much as we can */
-		res = bufferevent_read(bev, &is->buffer[is->rlen],
-		    is->length - is->rlen);
-		is->rlen += res;
-#ifdef DEBUG
-		{
-			int i;
-
-			printf("-> read %lu out of %lu from %s:%d:\n",
-			    is->rlen, is->length, is->host, is->port);
-			for (i = 0; i < (int)is->rlen; i++)
-				printf(isprint(is->buffer[i]) ? "%c" :
-				    "\\x%02x", (unsigned char)is->buffer[i]);
-			printf("\n");
-		}
-#endif
-		/* see you next time around */
-		if (is->rlen < is->length)
-			return;
-		/* nul-terminate the data */
-		is->buffer[MIN(is->rlen, ICB_MSGSIZE - 1)] = '\0';
-		/* process the message in full */
-		if (icb_input(is))
-			return;
-		/* cleanup the input buffer */
-		memset(is->buffer, 0, ICB_MSGSIZE);
-		is->rlen = is->length = 0;
-	}
-}
-
-void
-icbd_send(struct icb_session *is, char *buf, ssize_t size)
-{
-	if (bufferevent_write(is->bev, buf, size) == -1)
-		syslog(LOG_ERR, "bufferevent_write: %m");
-#ifdef DEBUG
-	{
-		int i;
-
-		printf("-> wrote %lu to %s:%d:\n", size, is->host, is->port);
-		for (i = 0; i < size; i++)
-			printf(isprint(buf[i]) ? "%c" : "\\x%02x",
-			    (unsigned char)buf[i]);
-		printf("\n");
-	}
-#endif
-}
-
-void
-icbd_drop(struct icb_session *is, char *reason)
-{
-	if (reason) {
-		icb_remove(is, reason);
-		icbd_log(is, LOG_DEBUG, reason);
-	} else
-		icb_remove(is, NULL);
-
-	/* cleanup the input buffer */
-	memset(is->buffer, 0, ICB_MSGSIZE);
-	is->rlen = is->length = 0;
-
-	(void)close(EVBUFFER_FD(is->bev));
-	bufferevent_free(is->bev);
-	if (!ISSETF(is->flags, ICB_SF_DNSINPROGRESS))
-		free(is);
-	else
-		SETF(is->flags, ICB_SF_PENDINGDROP);
-}
-
-void
-icbd_log(struct icb_session *is, int level, const char *fmt, ...)
-{
-	char buf[512];
-	va_list ap;
-
-	if (!verbose && level == LOG_DEBUG)
-		return;
-
-	va_start(ap, fmt);
-	(void)vsnprintf(buf, sizeof buf, fmt, ap);
-	va_end(ap);
-	if (is)
-		syslog(level, "%s:%u: %s", is->host, is->port, buf);
-	else
-		syslog(level, "%s", buf);
-}
-
-void
-icbd_restrict(void)
-{
-	struct stat	sb;
-	struct passwd	*pw;
-
-	if ((pw = getpwnam(ICBD_USER)) == NULL) {
-		syslog(LOG_ERR, "No passwd entry for %s", ICBD_USER);
-		exit(EX_NOUSER);
-	}
-
-	if (stat(pw->pw_dir, &sb) == -1) {
-		syslog(LOG_ERR, "%s: %m", pw->pw_name);
-		exit(EX_NOPERM);
-	}
-#ifdef __OpenBSD__
-	if (sb.st_uid != 0 || (sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
-		syslog(LOG_ERR, "bad directory permissions");
-		exit(EX_NOPERM);
-	}
-	if (chroot(pw->pw_dir) < 0) {
-		syslog(LOG_ERR, "%s: %m", pw->pw_dir);
-		exit(EX_UNAVAILABLE);
-	}
-
-	if (chdir("/") < 0) {
-		syslog(LOG_ERR, "/" ICBD_HOME ": %m");
-		exit(EX_UNAVAILABLE);
-	}
-
-	chdir(ICBD_HOME);
-#endif
-	if (setuid(pw->pw_uid) < 0) {
-		syslog(LOG_ERR, "%d: %m", pw->pw_uid);
-		exit(EX_NOPERM);
-	}
-
-#ifdef __OpenBSD__
-	if (dodns) {
-		if (pledge("stdio inet rpath dns", NULL) == -1) {
-			syslog(LOG_ERR, "pledge");
-			exit(EX_NOPERM);
-		}
-	} else {
-		if (pledge("stdio inet rpath", NULL) == -1) {
-			syslog(LOG_ERR, "pledge");
-			exit(EX_NOPERM);
-		}
-	}
-#endif
-
-	(void)setproctitle("icbd");
-}
-
-void
-icbd_modupdate(void)
-{
-	struct stat st;
-	FILE *fp;
-	char *buf, *lbuf;
-	size_t len;
-
-	if (strlen(modtabpath) == 0)
-		return;
-	if (stat(modtabpath, &st)) {
-		syslog(LOG_ERR, "stat %s: %m", modtabpath);
-		return;
-	}
-	/* see if there are any changes */
-	if (timespeccmp(&st.st_mtim, &modtabst.st_mtim, ==) ||
-	    st.st_size == 0)
-		return;
-
-	if ((fp = fopen(modtabpath, "r")) == NULL) {
-		syslog(LOG_ERR, "open %s: %m", modtabpath);
-		return;
-	}
-
-	modtabcnt = 0;
-	bzero(modtab, ICB_MTABLEN * ICB_MAXNICKLEN);
-	lbuf = NULL;
-	while ((buf = fgetln(fp, &len)) && modtabcnt < ICB_MTABLEN) {
-		if (buf[len - 1] == '\n')
-			buf[len - 1] = '\0';
-		else {
-			/* EOF without EOL, copy and add the NUL */
-			if ((lbuf = malloc(len + 1)) == NULL)
-				err(1, NULL);
-			memcpy(lbuf, buf, len);
-			lbuf[len] = '\0';
-			buf = lbuf;
-		}
-		while (buf[0] == ' ' || buf[0] == '\t')
-			buf++;
-		if (buf[0] == '#' || buf[0] == '\0')
-			continue;
-		strlcpy(modtab[modtabcnt++], buf, ICB_MAXNICKLEN);
-	}
-	free(lbuf);
-
-	qsort(modtab, modtabcnt, ICB_MAXNICKLEN,
-	    (int (*)(const void *, const void *))strcmp);
-
-	fclose(fp);
-
-	memcpy(&modtabst, &st, sizeof modtabst);
-}
-
-time_t
-getmonotime(void)
-{
-	struct timespec ts;
-
-	if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
-		syslog(LOG_ERR, "%m");
-		exit(EX_OSERR);
-	}
-	return (ts.tv_sec);
-}
-
-void
-getpeerinfo(struct icb_session *is)
-{
-	struct sockaddr_in *sin = (struct sockaddr_in *)&is->ss;
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&is->ss;
-	socklen_t ss_len = sizeof is->ss;
-
-	bzero(&is->ss, sizeof is->ss);
-	if (getpeername(EVBUFFER_FD(is->bev), (struct sockaddr *)&is->ss,
-	    &ss_len) != 0)
-		return;
-
-	is->port = 0;
-	switch (is->ss.ss_family) {
-	case AF_INET:
-		is->port = ntohs(sin->sin_port);
-		break;
-
-	case AF_INET6:
-		is->port = ntohs(sin6->sin6_port);
-		break;
-	}
-
-	inet_ntop(is->ss.ss_family, is->ss.ss_family == AF_INET ?
-	    (void *)&sin->sin_addr : (void *)&sin6->sin6_addr,
-	    is->host, sizeof is->host);
-
-	dns_resolve(is);
-}
Index: bd.h
===================================================================
--- icbd.h	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,42 +1,0 @@
-/*
- * Copyright (c) 2009 Mike Belopuhov
- *
- * 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.
- */
-
-#define ICBD_USER	"_icbd"
-#define ICBD_HOME	"core"
-
-#define TCP_BACKLOG	5
-
-#ifndef MIN
-#define MIN(x, y)	((x) < (y) ? (x) : (y))
-#endif
-
-#define EVBUFFER_FD(x)	(EVENT_FD(&(x)->ev_read))
-
-extern int verbose;
-
-/* icbd.c */
-void		icbd_drop(struct icb_session *, char *);
-void		icbd_log(struct icb_session *, int, const char *, ...);
-void		icbd_send(struct icb_session *, char *, ssize_t);
-void		icbd_modupdate(void);
-time_t		getmonotime(void);
-
-/* dns.c */
-void		dns_resolve(struct icb_session *);
-
-/* logger.c */
-int		logger_init(void);
-void		logger(char *, char *, char *);
Index: gger.c
===================================================================
--- logger.c	(revision 4a74b5bcfc9449be0d22257a0f73f116301f7f0e)
+++ 	(revision )
@@ -1,320 +1,0 @@
-/*
- * Copyright (c) 2009 Michael Shalayeff
- * Copyright (c) 2014 Mike Belopuhov
- * Copyright (c) 2024 Nishi
- * Copyright (c) 2025 Izuru Yakumo
- *
- * 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 MIND, 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/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-#include <errno.h>
-#include <limits.h>
-#include <netdb.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <syslog.h>
-#include <sysexits.h>
-#include <time.h>
-#include <event.h>
-#include <pwd.h>
-
-#include "icb.h"
-#include "icbd.h"
-
-void logger_ioerr(struct bufferevent *, short, void *);
-void logger_dispatch(struct bufferevent *, void *);
-FILE *logger_open(char *);
-void logger_tick(void);
-
-struct icbd_logentry {
-	char	group[ICB_MAXGRPLEN];
-	char	nick[ICB_MAXNICKLEN];
-	size_t	length;
-};
-
-struct {
-	char	group[ICB_MAXGRPLEN];
-	FILE	*fp;
-} logfiles[10];
-int nlogfiles;
-
-int logger_pipe;
-
-char file_ts[sizeof "0000-00"];
-char line_ts[sizeof "00:00"];
-struct event ev_tick;
-
-extern char logprefix[PATH_MAX/2];
-extern int dologging;
-
-int
-logger_init(void)
-{
-	struct bufferevent *bev;
-	struct passwd *pw;
-	int pipes[2];
-
-	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipes) == -1) {
-		syslog(LOG_ERR, "%s: socketpair: %m", __func__);
-		exit(EX_OSERR);
-	}
-
-	switch (fork()) {
-	case -1:
-		syslog(LOG_ERR, "%s: fork: %m", __func__);
-		exit(EX_OSERR);
-	case 0:
-		break;
-
-	default:
-		close(pipes[1]);
-		logger_pipe = pipes[0];
-		return (0);
-	}
-
-	setproctitle("logger");
-	close(pipes[0]);
-
-	if ((pw = getpwnam(ICBD_USER)) == NULL) {
-		syslog(LOG_ERR, "%s: No passwd entry for %s", __func__,
-		    ICBD_USER);
-		exit(EX_NOUSER);
-	}
-#ifdef __OpenBSD
-	if (chroot(pw->pw_dir) < 0) {
-		syslog(LOG_ERR, "%s: %s: %m", __func__, pw->pw_dir);
-		exit(EX_UNAVAILABLE);
-	}
-
-	if (chdir("/") < 0) {
-		syslog(LOG_ERR, "%s: chdir: %m", __func__);
-		exit(EX_UNAVAILABLE);
-	}
-
-	chdir (ICBD_HOME);
-
-	if (setuid(pw->pw_uid) < 0) {
-		syslog(LOG_ERR, "%s: %d: %m", __func__, pw->pw_uid);
-		exit(EX_NOPERM);
-	}
-#endif
-#ifdef __OpenBSD__
-	if (pledge("stdio cpath wpath", NULL) == -1) {
-		syslog(LOG_ERR, "%s: pledge", __func__);
-		exit(EX_NOPERM);
-	}
-#endif
-
-	event_init();
-
-	/* event for message processing */
-	if ((bev = bufferevent_new(pipes[1], logger_dispatch, NULL,
-	    logger_ioerr, NULL)) == NULL) {
-		syslog(LOG_ERR, "%s: bufferevent_new: %m", __func__);
-		exit(EX_UNAVAILABLE);
-	}
-	if (bufferevent_enable(bev, EV_READ)) {
-		syslog(LOG_ERR, "%s: bufferevent_enable: %m", __func__);
-		bufferevent_free(bev);
-		exit(EX_UNAVAILABLE);
-	}
-
-	evtimer_set(&ev_tick, (void (*)(int, short, void *))logger_tick, NULL);
-	logger_tick();
-	return event_dispatch();
-}
-
-void
-logger_ioerr(struct bufferevent *bev __attribute__((__unused__)), short what,
-    void *arg __attribute__((__unused__)))
-{
-	const char *cause = NULL;
-
-	if (what & EVBUFFER_TIMEOUT)
-		cause = "timeout";
-	else if (what & EVBUFFER_EOF)
-		cause = "eof";
-	else if (what & EVBUFFER_ERROR)
-		cause = what & EVBUFFER_READ ? "read" : "write";
-	syslog(LOG_ERR, "%s: %s", __func__, cause ? cause : "unknown");
-	exit(EX_IOERR);
-}
-
-void
-logger_dispatch(struct bufferevent *bev, void *arg __attribute__((unused)))
-{
-	struct icbd_logentry *e;
-	static char buf[sizeof *e + ICB_MSGSIZE];
-	static size_t nread = 0;
-	FILE *fp = NULL;
-	size_t res;
-	char *m;
-	int i;
-
-	e = (struct icbd_logentry *)buf;
-	m = buf + sizeof *e;
-
-	while (EVBUFFER_LENGTH(EVBUFFER_INPUT(bev)) > 0) {
-		if (nread == 0) {
-			bzero(e, sizeof *e);
-			/* read the log entry header */
-			res = bufferevent_read(bev, &buf[0], sizeof *e);
-			nread += res;
-			if (nread < sizeof *e)
-				return;
-		}
-		/* see if we got the whole header */
-		if (nread < sizeof *e) {
-			/* finish reading */
-			res = bufferevent_read(bev, &buf[nread],
-			    sizeof *e - nread);
-			nread += res;
-			if (nread < sizeof *e)
-				return;
-		}
-		if (e->length >= ICB_MSGSIZE) {
-			syslog(LOG_ERR, "%s: message too big: %lu", __func__,
-			    e->length);
-			exit(EX_DATAERR);
-		}
-		/* fetch the message */
-		res = bufferevent_read(bev, &buf[nread],
-		    e->length - (nread - sizeof *e));
-		nread += res;
-		if (nread - sizeof *e < e->length)
-			return;
-#ifdef DEBUG
-		{
-			printf("logger read %lu\n", nread - sizeof *e);
-			for (i = 0; i < (int)(nread - sizeof *e); i++)
-				printf(" %02x", (unsigned char)m[i]);
-			printf("\n");
-		}
-#endif
-		/* terminate the buffer */
-		m[MIN(nread - sizeof *e, ICB_MSGSIZE - 1)] = '\0';
-		/* find the appropriate log file */
-		for (i = 0; i < nlogfiles; i++)
-			if (strcmp(logfiles[i].group, e->group) == 0)
-				fp = logfiles[i].fp;
-		if (!fp && (fp = logger_open(e->group)) == NULL)
-			return;
-		if (strlen(e->nick) == 0)
-			fprintf(fp, "[%s] %s\n", line_ts, m);
-		else
-			fprintf(fp, "[%s] <%s> %s\n", line_ts, e->nick, m);
-		/* get ready for the next message */
-		nread = 0;
-	}
-}
-
-FILE *
-logger_open(char *group)
-{
-	char path[PATH_MAX];
-	FILE *fp = NULL;
-
-	/* make sure not to overflow the logfiles table */
-	if (nlogfiles == nitems(logfiles)) {
-		syslog(LOG_NOTICE, "%s: logfiles table is full", __func__);
-		return (NULL);
-	}
-	snprintf(path, sizeof path, "%s/%s", logprefix, group);
-	if (mkdir(path, 0755) < 0 && errno != EEXIST) {
-		syslog(LOG_ERR, "%s: %s: %m", __func__, group);
-		return (NULL);
-	}
-	snprintf(path, sizeof path, "%s/%s/%s", logprefix, group, file_ts);
-	if ((fp = fopen(path, "a")) == NULL) {
-		syslog(LOG_ERR, "%s: %s: %m", __func__, path);
-		return (NULL);
-	}
-	setvbuf(fp, NULL, _IOLBF, 0);
-	if (verbose)
-		syslog(LOG_NOTICE, "%s: %s", __func__, path);
-	strlcpy(logfiles[nlogfiles].group, group, ICB_MAXGRPLEN);
-	logfiles[nlogfiles++].fp = fp;
-	return (fp);
-}
-
-void
-logger(char *group, char *nick, char *what)
-{
-	struct icbd_logentry e;
-	struct iovec iov[2];
-	const char *defgrp = "1";
-
-	if (!dologging)
-		return;
-
-	if (strcmp(group, defgrp) == 0)
-		return;
-
-	strlcpy(e.group, group, ICB_MAXGRPLEN);
-	strlcpy(e.nick, nick, ICB_MAXNICKLEN);
-	e.length = strlen(what) + 1;
-
-	iov[0].iov_base = &e;
-	iov[0].iov_len = sizeof e;
-
-	iov[1].iov_base = what;
-	iov[1].iov_len = e.length;
-
-	if (writev(logger_pipe, iov, 2) == -1)
-		syslog(LOG_ERR, "%s: %m", __func__);
-}
-
-void
-logger_tick(void)
-{
-	static int last_mon = -1, last_mday = -1;
-	struct timeval tv = { 60, 0 };
-	char buf[128];
-	struct tm *tm;
-	time_t t;
-	int i;
-
-	time(&t);
-	tm = gmtime(&t);
-	if (last_mon != tm->tm_mon) {
-		snprintf(file_ts, sizeof file_ts, "%04d-%02d",
-		    tm->tm_year + 1900, tm->tm_mon + 1);
-		last_mon = tm->tm_mon;
-		/* rotate log files */
-		for (i = 0; i < nlogfiles; i++) {
-			fclose(logfiles[i].fp);
-			logfiles[i].fp = NULL;
-		}
-		nlogfiles = 0;
-	}
-	if (tm->tm_mday != last_mday) {
-		strftime(buf, sizeof(buf),
-		    "Today is %a %b %e %Y %H:%M %Z (%z)", tm);
-		for (i = 0; i < nlogfiles; i++)
-			fprintf(logfiles[i].fp, "%s\n", buf);
-		last_mday = tm->tm_mday;
-	}
-	snprintf(line_ts, sizeof line_ts, "%02d:%02d", tm->tm_hour,
-	    tm->tm_min);
-	if (evtimer_add(&ev_tick, &tv) < 0) {
-		syslog(LOG_ERR, "%s: evtimer_add: %m", __func__);
-		exit(EX_UNAVAILABLE);
-	}
-}
